diff options
Diffstat (limited to 'include/boost')
32 files changed, 0 insertions, 6490 deletions
diff --git a/include/boost/sqlite.hpp b/include/boost/sqlite.hpp deleted file mode 100644 index 474102a..0000000 --- a/include/boost/sqlite.hpp +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2022 Klemens D. Morgenstern -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_SQLITE_HPP -#define BOOST_SQLITE_HPP - -/** @defgroup reference Reference - * - * This page contains the documentation of the sqlite high-level API. - */ - -#include <boost/sqlite/backup.hpp> -#include <boost/sqlite/blob.hpp> -#include <boost/sqlite/collation.hpp> -#include <boost/sqlite/connection.hpp> -#include <boost/sqlite/cstring_ref.hpp> -#include <boost/sqlite/error.hpp> -#include <boost/sqlite/field.hpp> -#include <boost/sqlite/function.hpp> -#include <boost/sqlite/meta_data.hpp> -#include <boost/sqlite/memory.hpp> -#include <boost/sqlite/hooks.hpp> -#include <boost/sqlite/json.hpp> -#include <boost/sqlite/resultset.hpp> -#include <boost/sqlite/row.hpp> -#include <boost/sqlite/statement.hpp> -#include <boost/sqlite/static_resultset.hpp> -#include <boost/sqlite/string.hpp> -#include <boost/sqlite/transaction.hpp> -#include <boost/sqlite/value.hpp> -#include <boost/sqlite/vtable.hpp> - -#if defined(BOOST_SQLITE_COMPILE_EXTENSION) -#include <boost/sqlite/extension.hpp> -#endif - -#endif //BOOST_SQLITE_HPP diff --git a/include/boost/sqlite/allocator.hpp b/include/boost/sqlite/allocator.hpp deleted file mode 100644 index f449475..0000000 --- a/include/boost/sqlite/allocator.hpp +++ /dev/null @@ -1,48 +0,0 @@ -// -// Copyright (c) 2022 Klemens Morgenstern (klemens.morgenstern@gmx.net) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BOOST_SQLITE_ALLOCATOR_HPP -#define BOOST_SQLITE_ALLOCATOR_HPP - -#include <boost/sqlite/detail/config.hpp> - -#include <cstddef> -#include <cstdint> - -BOOST_SQLITE_BEGIN_NAMESPACE - -template<typename T> -struct allocator -{ - constexpr allocator() noexcept {} - constexpr allocator( const allocator& other ) noexcept {} - template< class U > - constexpr allocator( const allocator<U>& other ) noexcept {} - -#if defined(SQLITE_4_BYTE_ALIGNED_MALLOC) - constexpr static std::size_t alignment = 4u; -#else - constexpr static std::size_t alignment = 8u; -#endif - - static_assert(alignof(T) <= alignment, "T alignment can't be fulfilled by sqlite"); - [[nodiscard]] T* allocate( std::size_t n ) - { - auto p = static_cast<T*>(sqlite3_malloc64(n * sizeof(T))); - if (p == nullptr) - boost::throw_exception(std::bad_alloc()); - return p; - } - void deallocate( T* p, std::size_t) - { - return sqlite3_free(p); - } -}; - -BOOST_SQLITE_END_NAMESPACE - -#endif //BOOST_SQLITE_ALLOCATOR_HPP diff --git a/include/boost/sqlite/backup.hpp b/include/boost/sqlite/backup.hpp deleted file mode 100644 index 737a28e..0000000 --- a/include/boost/sqlite/backup.hpp +++ /dev/null @@ -1,74 +0,0 @@ -// -// Copyright (c) 2022 Klemens Morgenstern (klemens.morgenstern@gmx.net) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BOOST_SQLITE_BACKUP_HPP -#define BOOST_SQLITE_BACKUP_HPP - -#include <boost/sqlite/detail/config.hpp> -#include <boost/sqlite/cstring_ref.hpp> -#include <boost/sqlite/error.hpp> - -BOOST_SQLITE_BEGIN_NAMESPACE - -struct connection ; - -///@{ -/** - @brief Backup a database - @ingroup reference - - This function will create a backup of an existing database. - This can be useful to write an in memory database to disk et vice versa. - - @param source The source database to backup - @param target The target of the backup - @param source_name The source database to read the backup from. Default is 'main'. - @param target_name The target database to write the backup to. Default is 'main'. - - @par Error Handling - - @throws system_error from overload without `ec` & `ei` - - or you need to pass - - @param ec The system::error_code to capture any possibly errors - @param ei Additional error_info when error occurs. - - @par Example - - @code{.cpp} - - sqlite::connection conn{":memory:"}; - { - sqlite::connection read{"./read_only_db.db", SQLITE_READONLY}; - backup(read, target); - } - - @endcode - */ -BOOST_SQLITE_DECL -void -backup(connection & source, - connection & target, - cstring_ref source_name, - cstring_ref target_name, - system::error_code & ec, - error_info & ei); - -BOOST_SQLITE_DECL -void -backup(connection & source, - connection & target, - cstring_ref source_name = "main", - cstring_ref target_name = "main"); - -///@} - -BOOST_SQLITE_END_NAMESPACE - - -#endif //BOOST_SQLITE_BACKUP_HPP diff --git a/include/boost/sqlite/blob.hpp b/include/boost/sqlite/blob.hpp deleted file mode 100644 index cd82363..0000000 --- a/include/boost/sqlite/blob.hpp +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright (c) 2022 Klemens D. Morgenstern -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_SQLITE_BLOB_HPP -#define BOOST_SQLITE_BLOB_HPP - -#include <boost/sqlite/detail/config.hpp> -#include <boost/sqlite/memory.hpp> -#include <boost/sqlite/error.hpp> -#include <type_traits> -#include <memory> -#include <cstring> - -BOOST_SQLITE_BEGIN_NAMESPACE - -struct connection ; - -/// @brief a view to a binary large object @ingroup reference -struct blob_view -{ - /// The data in the blob - const void * data() const {return data_;} - /// The size of the data int he blob, in bytes - std::size_t size() const {return size_;} - /// Construct a blob - blob_view(const void * data, std::size_t size) : data_(data), size_(size) {} - - /// Construct an empty blob - blob_view() = default; - /// Construct a blob from some other blob-like structure. - template<typename T> - explicit blob_view(const T & value, - typename std::enable_if< - std::is_pointer<decltype(std::declval<T>().data())>::value - && std::is_convertible<decltype(std::declval<T>().size()), std::size_t>::value - >::type * = nullptr) : data_(value.data()), size_(value.size()) {} - - inline blob_view(const struct blob & b); - private: - const void * data_{nullptr}; - std::size_t size_{0u}; -}; - -/// @brief Helper type to pass a blob full of zeroes without allocating extra memory. @ingroup reference -enum class zero_blob : sqlite3_uint64 {}; - -/// @brief An object that owns a binary large object. @ingroup reference -struct blob -{ - /// The data in the blob - void * data() const {return impl_.get();} - /// The size of the data int he blob, in bytes - std::size_t size() const {return size_;} - - /// Create a blob from a blob_view - explicit blob(blob_view bv) - { - impl_.reset(sqlite3_malloc(static_cast<int>(bv.size()))); - size_ = bv.size(); - std::memcpy(impl_.get(), bv.data(), size_); - } - /// Create an empty blob with size `n`. - explicit blob(std::size_t n) : impl_(sqlite3_malloc(static_cast<int>(n))), size_(n) {} - - /// Construct an empty blob - constexpr blob() = default; - /// Release & take ownership of the blob. - void * release() && {return std::move(impl_).release(); } - private: - unique_ptr<void> impl_; - std::size_t size_{0u}; -}; - -blob_view::blob_view(const blob & b) : data_(b.data()), size_(b.size()) {} - -/// @brief 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. Takes owner ship - explicit blob_handle(sqlite3_blob * blob) : blob_(blob) {} - - ///@{ - /// @brief Reopen on another row - BOOST_SQLITE_DECL - void reopen(sqlite3_int64 row_id, system::error_code & ec); - BOOST_SQLITE_DECL - void reopen(sqlite3_int64 row_id); - ///@} - - ///@{ - /// @brief Read data from the blob - BOOST_SQLITE_DECL - void read_at(void *data, int len, int offset, system::error_code &ec); - BOOST_SQLITE_DECL - void read_at(void *data, int len, int offset); - ///@} - - ///@{ - /// @brief Write data to the blob - BOOST_SQLITE_DECL - void write_at(const void *data, int len, int offset, system::error_code &ec); - BOOST_SQLITE_DECL - void write_at(const void *data, int len, int offset); - ///@} - - /// The size of the blob - std::size_t size() const {return static_cast<std::size_t>(sqlite3_blob_bytes(blob_.get()));} - - /// The handle of the blob - using handle_type = sqlite3_blob*; - /// Returns the handle of the blob - handle_type handle() { return blob_.get(); } - /// Release the owned handle. - handle_type release() && { return blob_.release(); } - private: - struct deleter_ - { - void operator()(sqlite3_blob *impl) - { - sqlite3_blob_close(impl); - } - }; - std::unique_ptr<sqlite3_blob, deleter_> blob_; -}; - -///@{ -/// Open a blob for incremental access -BOOST_SQLITE_DECL -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); - -BOOST_SQLITE_DECL -blob_handle open_blob(connection & conn, - cstring_ref db, - cstring_ref table, - cstring_ref column, - sqlite3_int64 row, - bool read_only = false); -///}@ - - - -BOOST_SQLITE_END_NAMESPACE - - -#endif //BOOST_SQLITE_BLOB_HPP diff --git a/include/boost/sqlite/collation.hpp b/include/boost/sqlite/collation.hpp deleted file mode 100644 index a4624c4..0000000 --- a/include/boost/sqlite/collation.hpp +++ /dev/null @@ -1,140 +0,0 @@ -// -// Copyright (c) 2022 Klemens Morgenstern (klemens.morgenstern@gmx.net) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BOOST_SQLITE_COLLATION_HPP -#define BOOST_SQLITE_COLLATION_HPP - -#include <boost/sqlite/connection.hpp> -#include <boost/sqlite/detail/exception.hpp> - -BOOST_SQLITE_BEGIN_NAMESPACE - -///@{ -/** Define a custom collation function - @ingroup reference - - @param conn A connection to the database in which to install the collation. - @param name The name of the collation. - @param func The function - - The function must be callable with two `string_view` and return an int, indicating the comparison results. - - @par Example - - @code{.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;"); - - @endcode - - */ - -template<typename Func> -void create_collation( - connection & conn, - cstring_ref name, - Func && func, - typename std::enable_if< - std::is_convertible< - decltype(func(string_view(), string_view())), - int>::value, - system::error_code>::type & ec) -{ - using func_type = typename std::decay<Func>::type; - unique_ptr<func_type> f{new (memory_tag{}) func_type(std::forward<Func>(func))}; - if (f == nullptr) - { - BOOST_SQLITE_ASSIGN_EC(ec, SQLITE_NOMEM); - return; - } - auto res = sqlite3_create_collation_v2( - conn.handle(), - name.c_str(), - SQLITE_UTF8, - f.get(), - +[](void * data, int len_l, const void * str_l, int len_r, const void * str_r) -> int - { - string_view l(static_cast<const char*>(str_l), len_l); - string_view r(static_cast<const char*>(str_r), len_r); - auto & impl = (*static_cast<func_type*>(data)); - static_assert(noexcept(impl(l, r)), - "Collation function must be noexcept"); - return impl(l, r); - }, - +[](void * p) { delete_(static_cast<func_type*>(p)); } - ); - - if (res != SQLITE_OK) - BOOST_SQLITE_ASSIGN_EC(ec, res); - else - f.release(); -} - - -template<typename Func> -auto create_collation( - connection & conn, - cstring_ref name, - Func && func) -#if !defined(BOOST_SQLITE_GENERATING_DOCS) - -> typename std::enable_if< - std::is_convertible< - decltype(func(string_view(), string_view())), - int>::value>::type -#endif -{ - system::error_code ec; - create_collation(conn, name, std::forward<Func>(func), ec); - if (ec) - detail::throw_error_code(ec, BOOST_CURRENT_LOCATION); -} - - -inline void delete_collation( - connection & conn, - cstring_ref name, - system::error_code & ec) -{ - auto res = sqlite3_create_collation_v2( - conn.handle(), - name.c_str(), - SQLITE_UTF8, - nullptr, nullptr, nullptr); - if (res != SQLITE_OK) - { - BOOST_SQLITE_ASSIGN_EC(ec, res); - } -} - - -inline auto delete_collation( - connection & conn, - cstring_ref name) -{ - system::error_code ec; - delete_collation(conn, name, ec); - if (ec) - detail::throw_error_code(ec, BOOST_CURRENT_LOCATION); -} - -/// @} - -BOOST_SQLITE_END_NAMESPACE - -#endif //BOOST_SQLITE_COLLATION_HPP diff --git a/include/boost/sqlite/connection.hpp b/include/boost/sqlite/connection.hpp deleted file mode 100644 index 0f6ccf8..0000000 --- a/include/boost/sqlite/connection.hpp +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright (c) 2022 Klemens D. Morgenstern -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_SQLITE_CONNECTION_HPP -#define BOOST_SQLITE_CONNECTION_HPP - -#include <boost/sqlite/detail/config.hpp> -#include <boost/sqlite/error.hpp> -#include <boost/sqlite/resultset.hpp> -#include <boost/sqlite/statement.hpp> -#include <memory> -#include <boost/system/system_error.hpp> - -BOOST_SQLITE_BEGIN_NAMESPACE - -template<typename T, bool Strict> -struct static_resultset; - -constexpr static cstring_ref in_memory = ":memory:"; - -/** @brief main object for a connection to a database. - @ingroup reference - - @par Example - @code{.cpp} - sqlite::connection conn; - conn.connect("./my-database.db"); - conn.prepare("insert into log (text) values ($1)").execute(std::make_tuple("booting up")); - @endcode - - */ -struct connection -{ - /// The handle of the connection - using handle_type = sqlite3*; - /// Returns the handle - handle_type handle() const { return impl_.get(); } - /// Release the owned handle. - handle_type release() && { return impl_.release(); } - - ///Default constructor - connection() = default; - /// Construct the connection from a handle. - explicit connection(handle_type handle, bool take_ownership = true) : impl_(handle, take_ownership) {} - /// 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. @see https://www.sqlite.org/c3ref/c_open_autoproxy.html - connection(cstring_ref filename, - int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE) { connect(filename, flags); } - -#if defined(BOOST_WINDOWS_API) - template<typename Path, - typename = std::enable_if_t< - std::is_same<typename Path::string_type, std::wstring>::value && - std::is_constructible<cstring_ref, decltype(std::declval<Path>().string())>::value - >> - explicit connection(const Path & pth) : connection(pth.string()) {} -#endif - ///@{ - /// Connect the database to `filename`. `flags` is set by `SQLITE_OPEN_*` flags. - BOOST_SQLITE_DECL void connect(cstring_ref filename, int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); - BOOST_SQLITE_DECL void connect(cstring_ref filename, int flags, system::error_code & ec); - ///@} - -#if defined(BOOST_WINDOWS_API) - template<typename Path, - typename = std::enable_if_t< - std::is_same<typename Path::string_type, std::wstring>::value && - std::is_constructible<cstring_ref, decltype(std::declval<Path>().string())>::value - >> - void connect(const Path & pth, int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE) - { - connect(pth.string(), flags); - } - - - template<typename Path, - typename = std::enable_if_t< - std::is_same<typename Path::string_type, std::wstring>::value && - std::is_constructible<cstring_ref, decltype(std::declval<Path>().string())>::value - >> - void connect(const Path & pth, int flags, system::error_code & ec) - { - connect(pth.string(), flags, ec); - } -#endif - - ///@{ - /// Close the database connection. - BOOST_SQLITE_DECL void close(); - BOOST_SQLITE_DECL void close(system::error_code & ec, error_info & ei); - ///@} - - /// Check if the database holds a valid handle. - bool valid() const {return impl_ != nullptr;} - - - ///@{ - /// Perform a query without parameters. Can only execute a single statement. - BOOST_SQLITE_DECL resultset query( - core::string_view q, - system::error_code & ec, - error_info & ei); - - BOOST_SQLITE_DECL 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) - { - static_resultset<T, Strict> tmp = query(q, ec, ei); - if (ec) - return {}; - tmp.check_columns_(ec, ei); - if (ec) - return {}; - - return tmp; - } - - template<typename T, bool Strict = false> - static_resultset<T, Strict> query(core::string_view q) - { - system::error_code ec; - error_info ei; - auto tmp = query<T, Strict>(q, ec, ei); - if (ec) - throw_exception(system::system_error(ec, ei.message())); - return tmp; - } - ///@} - - ///@{ - /// Perform a query without parametert, It execute a multiple statement. - BOOST_SQLITE_DECL void execute( - cstring_ref q, - system::error_code & ec, - error_info & ei); - - BOOST_SQLITE_DECL void execute(cstring_ref q); - - template<typename StringLike, - typename = decltype(std::declval<const StringLike&>().c_str())> - void execute( - const StringLike& q, - system::error_code & ec, - error_info & ei) - { - execute(q.c_str(), ec, ei); - } - template<typename StringLike, - typename = decltype(std::declval<const StringLike&>().c_str())> - void execute(const StringLike & q) { execute(q.c_str());} - ///@} - - ///@{ - /// Perform a query with parameters. Can only execute a single statement. - BOOST_SQLITE_DECL statement prepare( - core::string_view q, - system::error_code & ec, - error_info & ei); - - BOOST_SQLITE_DECL 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 - { - return sqlite3_table_column_metadata(impl_.get(), db_name.c_str(), table.c_str(), - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr) - == SQLITE_OK; - } - - /// Check if the database has the table - bool has_column( - cstring_ref table, - cstring_ref column, - cstring_ref db_name = "main") const - { - return sqlite3_table_column_metadata(impl_.get(), db_name.c_str(), table.c_str(), column.c_str(), - nullptr, nullptr, nullptr, nullptr, nullptr) - == SQLITE_OK; - } - private: - struct deleter_ - { - deleter_(bool owned = true) : owned_(owned) {} - bool owned_ = true; - void operator()(sqlite3 *impl) - { - if (owned_) - sqlite3_close_v2(impl); - } - }; - - std::unique_ptr<sqlite3, deleter_> impl_{nullptr, deleter_{}}; -}; - -BOOST_SQLITE_END_NAMESPACE - - -#endif //BOOST_SQLITE_CONNECTION_HPP diff --git a/include/boost/sqlite/cstring_ref.hpp b/include/boost/sqlite/cstring_ref.hpp deleted file mode 100644 index 6747f45..0000000 --- a/include/boost/sqlite/cstring_ref.hpp +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright (c) 2022 Klemens D. Morgenstern -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// based on boost.process -#ifndef BOOST_SQLITE_CSTRING_REF_HPP -#define BOOST_SQLITE_CSTRING_REF_HPP - -#include <boost/config.hpp> -#include <boost/core/detail/string_view.hpp> - -#include <cstddef> -#include <type_traits> -#include <string> - - -#if __cplusplus >= 201702L -#include <string_view> -#endif - -namespace boost -{ -namespace sqlite -{ - -/// Small wrapper for a null-terminated string that can be directly passed to C APIS -/** This ref can only be modified by moving the front pointer. It does not store the - * size, but can detect values that can directly be passed to system APIs. - * - * It can be constructed from a `char*` pointer or any class that has a `c_str()` - * member function, e.g. std::string or boost::static_string. - * - */ -struct cstring_ref -{ - using value_type = char; - using traits_type = std::char_traits<char>; - BOOST_CONSTEXPR cstring_ref() noexcept : view_("") {} - BOOST_CONSTEXPR cstring_ref(std::nullptr_t) = delete; - - BOOST_CONSTEXPR cstring_ref( const value_type* s ) : view_(s) {} - - template<typename Source, - typename = - typename std::enable_if< - std::is_same<const value_type, - typename std::remove_pointer<decltype(std::declval<Source>().c_str())>::type - >::value>::type> - BOOST_CONSTEXPR cstring_ref(Source && src) : view_(src.c_str()) {} - - BOOST_CONSTEXPR const char * c_str() const BOOST_NOEXCEPT - { - return this->data(); - } - - using string_view_type = core::string_view; - constexpr operator string_view_type() const {return view_;} - -#if __cplusplus >= 201702L - constexpr operator std::string_view() const {return view_;} -#endif - - using pointer = char *; - using const_pointer = const char *; - using reference = char &; - using const_reference = const char &; - using const_iterator = const_pointer; - using iterator = const_iterator; - using const_reverse_iterator = typename std::reverse_iterator<const_iterator>; - using reverse_iterator = typename std::reverse_iterator<iterator>; - using size_type = std::size_t; - using difference_type = std::ptrdiff_t; - - static BOOST_CONSTEXPR size_type npos = -1; - - BOOST_CONSTEXPR const_iterator begin() const BOOST_NOEXCEPT {return view_;}; - BOOST_CONSTEXPR const_iterator end() const BOOST_NOEXCEPT {return view_ + length();}; - BOOST_CONSTEXPR const_iterator cbegin() const BOOST_NOEXCEPT {return view_;}; - BOOST_CONSTEXPR const_iterator cend() const BOOST_NOEXCEPT {return view_ + length();}; - -#if defined(BOOST_NO_CXX17) - const_reverse_iterator rbegin() const BOOST_NOEXCEPT {return reverse_iterator(end());}; - const_reverse_iterator rend() const BOOST_NOEXCEPT {return reverse_iterator(begin());}; - const_reverse_iterator crbegin() const BOOST_NOEXCEPT {return reverse_iterator(end());}; - const_reverse_iterator crend() const BOOST_NOEXCEPT {return reverse_iterator(begin());}; -#else - BOOST_CONSTEXPR const_reverse_iterator rbegin() const BOOST_NOEXCEPT {return reverse_iterator(end());}; - BOOST_CONSTEXPR const_reverse_iterator rend() const BOOST_NOEXCEPT {return reverse_iterator(begin());}; - BOOST_CONSTEXPR const_reverse_iterator crbegin() const BOOST_NOEXCEPT {return reverse_iterator(end());}; - BOOST_CONSTEXPR const_reverse_iterator crend() const BOOST_NOEXCEPT {return reverse_iterator(begin());}; -#endif - - BOOST_CONSTEXPR size_type size() const BOOST_NOEXCEPT {return length(); } - BOOST_CONSTEXPR size_type length() const BOOST_NOEXCEPT {return length_impl_(); } - BOOST_CONSTEXPR size_type max_size() const BOOST_NOEXCEPT {return static_cast<std::size_t>(-1); } - BOOST_ATTRIBUTE_NODISCARD BOOST_CONSTEXPR bool empty() const BOOST_NOEXCEPT {return *view_ == '\0'; } - - BOOST_CONSTEXPR const_reference operator[](size_type pos) const {return view_[pos] ;} - BOOST_CXX14_CONSTEXPR const_reference at(size_type pos) const - { - if (pos >= size()) - throw_exception(std::out_of_range("cstring-view out of range")); - return view_[pos]; - } - BOOST_CONSTEXPR const_reference front() const {return *view_;} - BOOST_CONSTEXPR const_reference back() const {return view_[length() - 1];} - BOOST_CONSTEXPR const_pointer data() const BOOST_NOEXCEPT {return view_;} - BOOST_CXX14_CONSTEXPR void remove_prefix(size_type n) {view_ = view_ + n;} - void swap(cstring_ref& s) BOOST_NOEXCEPT {std::swap(view_, s.view_);} - - size_type copy(value_type* s, size_type n, size_type pos = 0) const - { - return traits_type::copy(s, view_ + pos, n) - view_; - } - BOOST_CONSTEXPR cstring_ref substr(size_type pos = 0) const - { - return cstring_ref(view_ + pos); - } - - BOOST_CXX14_CONSTEXPR string_view_type substr(size_type pos, size_type length) const - { - return string_view_type(view_).substr(pos, length); - } - - BOOST_CXX14_CONSTEXPR int compare(cstring_ref x) const BOOST_NOEXCEPT - { - auto idx = 0u; - for (; view_[idx] != null_char_()[0] && x[idx] != null_char_()[0]; idx++) - if (!traits_type::eq(view_[idx], x[idx])) - return traits_type::lt(view_[idx], x[idx]) ? -1 : 1; - - return traits_type::to_int_type(view_[idx]) - - traits_type::to_int_type(x[idx]); // will compare to null char of either. - } - - BOOST_CXX14_CONSTEXPR bool starts_with(string_view_type x) const BOOST_NOEXCEPT - { - if (x.empty()) - return true; - - auto idx = 0u; - for (; view_[idx] != null_char_()[0] && idx < x.size(); idx++) - if (!traits_type::eq(view_[idx], x[idx])) - return false; - - return idx == x.size() || view_[idx] != null_char_()[0]; - } - BOOST_CONSTEXPR bool starts_with(value_type x) const BOOST_NOEXCEPT - { - return traits_type::eq(view_[0], x); - } - - BOOST_CXX14_CONSTEXPR size_type find( char ch, size_type pos = 0 ) const BOOST_NOEXCEPT - { - for (auto p = view_ + pos; *p != *null_char_(); p++) - if (traits_type::eq(*p, ch)) - return p - view_; - return npos; - } - - - friend BOOST_CXX14_CONSTEXPR bool operator==(cstring_ref x, cstring_ref y) BOOST_NOEXCEPT - { - std::size_t idx = 0u; - for (idx = 0u; x[idx] != null_char_()[0] && y[idx] != null_char_()[0]; idx++) - if (!traits_type::eq(x[idx], y[idx])) - return false; - return x[idx] == y[idx]; - } - friend BOOST_CXX14_CONSTEXPR bool operator!=(cstring_ref x, cstring_ref y) BOOST_NOEXCEPT - { - std::size_t idx = 0u; - for (idx = 0u; x[idx] != null_char_()[0] && - y[idx] != null_char_()[0]; idx++) - if (!traits_type::eq(x[idx], y[idx])) - return true; - return x[idx] != y[idx]; - } - friend BOOST_CXX14_CONSTEXPR bool operator< (cstring_ref x, cstring_ref y) BOOST_NOEXCEPT {return x.compare(y) < 0;} - friend BOOST_CXX14_CONSTEXPR bool operator> (cstring_ref x, cstring_ref y) BOOST_NOEXCEPT {return x.compare(y) > 0;} - friend BOOST_CXX14_CONSTEXPR bool operator<=(cstring_ref x, cstring_ref y) BOOST_NOEXCEPT {return x.compare(y) <= 0;} - friend BOOST_CXX14_CONSTEXPR bool operator>=(cstring_ref x, cstring_ref y) BOOST_NOEXCEPT {return x.compare(y) >= 0;} - - // modifiers - void clear() BOOST_NOEXCEPT { view_ = null_char_(); } // Boost extension - - std::basic_string<value_type, traits_type> to_string() const - { - return std::basic_string<char, traits_type>(begin(), end()); - } - - template<typename Allocator> - std::basic_string<value_type, traits_type, Allocator> to_string(const Allocator& a) const - { - return std::basic_string<value_type, traits_type, Allocator>(begin(), end(), a); - } - - template<class A> operator std::basic_string<char, std::char_traits<char>, A>() const - { - return std::basic_string<char, std::char_traits<char>, A>( view_ ); - } - - private: - BOOST_CONSTEXPR static const_pointer null_char_() {return "\0";} - constexpr std::size_t length_impl_(std::size_t n = 0) const BOOST_NOEXCEPT - { - return view_[n] == null_char_()[0] ? n : length_impl_(n+1); - } - const_pointer view_; -}; - -template<typename Char> -inline std::basic_ostream<Char>& operator<<( std::basic_ostream<Char> & os, cstring_ref str ) -{ - return os << core::string_view(str); -} - - -} -} - - -#endif //BOOST_SQLITE_CSTRING_REF_HPP diff --git a/include/boost/sqlite/detail/aggregate_function.hpp b/include/boost/sqlite/detail/aggregate_function.hpp deleted file mode 100644 index de0c447..0000000 --- a/include/boost/sqlite/detail/aggregate_function.hpp +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright (c) 2023 Klemens D. Morgenstern -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_SQLITE_DETAIL_AGGREGATE_FUNCTION_HPP -#define BOOST_SQLITE_DETAIL_AGGREGATE_FUNCTION_HPP - -#include <boost/sqlite/detail/config.hpp> -#include <boost/sqlite/detail/catch.hpp> -#include <boost/sqlite/error.hpp> -#include <boost/sqlite/cstring_ref.hpp> -#include <boost/sqlite/memory.hpp> -#include <boost/sqlite/result.hpp> -#include <boost/sqlite/value.hpp> - -#include <boost/callable_traits/args.hpp> -#include <boost/callable_traits/return_type.hpp> -#include <boost/callable_traits/has_void_return.hpp> -#include <boost/core/span.hpp> - - -BOOST_SQLITE_BEGIN_NAMESPACE - -namespace detail -{ - -template<typename Func> -struct aggregate_function_maker -{ - void * mem; - - template<typename ... Args> - Func* operator()(Args && ... args) - { - return new (mem) Func(std::forward<Args>(args)...); - } -}; - -template<typename Func, typename Args> -int create_aggregate_function(sqlite3 * db, cstring_ref name, Args && args, int flags, - std::true_type /* void return */) -{ - using args_type = callable_traits::args_t<decltype(&Func::step)>; - using span_type = typename std::tuple_element<1U, args_type>::type; - using func_type = typename std::decay<Func>::type; - using func_args_type = typename std::decay<Args>::type; - - return sqlite3_create_function_v2( - db, name.c_str(), - span_type::extent == boost::dynamic_extent ? -1 : static_cast<int>(span_type::extent), - SQLITE_UTF8 | flags, - new (memory_tag{}) func_args_type(std::forward<Args>(args)), - nullptr, - +[](sqlite3_context* ctx, int len, sqlite3_value** args) - { - auto aa = reinterpret_cast<value*>(args); - auto fa = reinterpret_cast<func_args_type*>(sqlite3_user_data(ctx)); - auto c = static_cast<func_type*>(sqlite3_aggregate_context(ctx, 0)); - - execute_context_function( - ctx, - [&]() -> result<void> - { - if (c == nullptr) - { - auto p = sqlite3_aggregate_context(ctx, sizeof(func_type)); - if (!p) - return error(SQLITE_NOMEM); - c = mp11::tuple_apply(aggregate_function_maker<func_type>{p}, *fa); - } - c->step(span_type{aa, static_cast<std::size_t>(len)}); - return {}; - }); - }, - [](sqlite3_context* ctx) - { - auto fa = reinterpret_cast<func_args_type*>(sqlite3_user_data(ctx)); - auto c = static_cast<func_type*>(sqlite3_aggregate_context(ctx, 0)); - - execute_context_function( - ctx, - [&]() -> result<decltype(c->final())> - { - if (c == nullptr) - { - auto p = sqlite3_aggregate_context(ctx, sizeof(func_type)); - if (!p) - return error(SQLITE_NOMEM); - c = mp11::tuple_apply(aggregate_function_maker<func_type>{p}, *fa); - } - struct reaper {void operator()(func_type * c) { c->~func_type();}}; - std::unique_ptr<func_type, reaper> cl{c}; - return c->final(); - }); - }, - [](void * ptr) noexcept { delete_(static_cast<func_type*>(ptr));} - ); -} - - -template<typename Func, typename Args> -int create_aggregate_function(sqlite3 * db, cstring_ref name, Args && args, int flags, - std::false_type /* void return */) -{ - using args_type = callable_traits::args_t<decltype(&Func::step)>; - using span_type = typename std::tuple_element<1U, args_type>::type; - using func_type = typename std::decay<Func>::type; - using func_args_type = typename std::decay<Args>::type; - - return sqlite3_create_function_v2( - db, name.c_str(), - span_type::extent == boost::dynamic_extent ? -1 : static_cast<int>(span_type::extent), - SQLITE_UTF8 | flags, - new (memory_tag{}) func_args_type(std::forward<Args>(args)), - nullptr, - +[](sqlite3_context* ctx, int len, sqlite3_value** args) - { - auto aa = reinterpret_cast<value*>(args); - auto fa = reinterpret_cast<func_args_type*>(sqlite3_user_data(ctx)); - auto c = static_cast<func_type*>(sqlite3_aggregate_context(ctx, 0)); - - execute_context_function( - ctx, - [&]() -> result<void> - { - if (c == nullptr) - { - auto p = sqlite3_aggregate_context(ctx, sizeof(func_type)); - if (!p) - return {system::in_place_error, error(SQLITE_NOMEM)}; - c = mp11::tuple_apply(aggregate_function_maker<func_type>{p}, *fa); - } - return c->step(span_type{aa, static_cast<std::size_t>(len)}); - }); - }, - [](sqlite3_context* ctx) - { - auto fa = reinterpret_cast<func_args_type*>(sqlite3_user_data(ctx)); - auto c = static_cast<func_type*>(sqlite3_aggregate_context(ctx, 0)); - - execute_context_function( - ctx, - [&]() -> result<decltype(c->final())> - { - if (c == nullptr) - { - auto p = sqlite3_aggregate_context(ctx, sizeof(func_type)); - if (!p) - return {system::in_place_error, error(SQLITE_NOMEM)}; - c = mp11::tuple_apply(aggregate_function_maker<func_type>{p}, *fa); - } - struct reaper {void operator()(func_type * c) { c->~func_type();}}; - std::unique_ptr<func_type, reaper> cl{c}; - return c->final(); - }); - }, - [](void * ptr) noexcept { delete_(static_cast<func_type*>(ptr));} - ); -} - -} - -BOOST_SQLITE_END_NAMESPACE - - -#endif //BOOST_SQLITE_DETAIL_AGGREGATE_FUNCTION_HPP diff --git a/include/boost/sqlite/detail/catch.hpp b/include/boost/sqlite/detail/catch.hpp deleted file mode 100644 index e5b053f..0000000 --- a/include/boost/sqlite/detail/catch.hpp +++ /dev/null @@ -1,169 +0,0 @@ -// -// Copyright (c) 2022 Klemens Morgenstern (klemens.morgenstern@gmx.net) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BOOST_SQLITE_DETAIL_CATCH_HPP -#define BOOST_SQLITE_DETAIL_CATCH_HPP - -#include <boost/sqlite/detail/config.hpp> -#include <boost/sqlite/detail/exception.hpp> -#include <boost/sqlite/error.hpp> -#include <boost/sqlite/result.hpp> - -#include <boost/system/system_error.hpp> - -#include <stdexcept> - - -BOOST_SQLITE_BEGIN_NAMESPACE -namespace detail -{ - -template<typename Func, typename ... Args> -void execute_context_function_impl(std::false_type /* is_void */, - sqlite3_context * ctx, - Func && func, Args && ... args) - noexcept(noexcept(std::forward<Func>(func)(std::forward<Args>(args)...))) -{ - set_result(ctx, std::forward<Func>(func)(std::forward<Args>(args)...)); -} - -template<typename Func, typename ... Args> -void execute_context_function_impl(std::true_type /* is_void */, - sqlite3_context * ctx, - Func && func, Args && ... args) - noexcept(noexcept(std::forward<Func>(func)(std::forward<Args>(args)...))) -{ - std::forward<Func>(func)(std::forward<Args>(args)...); -} - -template<typename T> -int extract_error(char * &errMsg, result<T> & res) -{ - error err = std::move(res).error(); - if (err.info) - errMsg = err.info.release(); - return err.code; -} - - -template<typename Func, typename ... Args> -void execute_context_function(sqlite3_context * ctx, - Func && func, Args && ... args) noexcept -{ - using return_type = decltype(func(std::forward<Args>(args)...)); -#if !defined(BOOST_NO_EXCEPTIONS) - try - { -#endif - execute_context_function_impl(std::is_void<return_type>{}, ctx, - std::forward<Func>(func), - std::forward<Args>(args)...); -#if !defined(BOOST_NO_EXCEPTIONS) - } - catch(boost::system::system_error & se) - { - const auto msg = boost::sqlite::detail::get_message(se); - if (!msg.empty()) - sqlite3_result_error(ctx, msg.data(), msg.size()); - if (se.code().category() == boost::sqlite::sqlite_category()) - sqlite3_result_error_code(ctx, se.code().value()); - } - catch(std::bad_alloc &) { sqlite3_result_error_nomem(ctx); } - catch(std::length_error &) { sqlite3_result_error_toobig(ctx); } - catch(std::out_of_range &) { sqlite3_result_error_code(ctx, SQLITE_RANGE);} - catch(std::logic_error &le) - { - sqlite3_result_error(ctx, le.what(), std::strlen(le.what())); - sqlite3_result_error_code(ctx, SQLITE_MISUSE); - } - catch(std::exception & ex) - { - sqlite3_result_error(ctx, ex.what(), std::strlen(ex.what())); - } - catch(...) {sqlite3_result_error_code(ctx, SQLITE_ERROR); } -#endif -} - -} -BOOST_SQLITE_END_NAMESPACE - -#if defined(BOOST_NO_EXCEPTIONS) -#define BOOST_SQLITE_TRY -#define BOOST_SQLITE_CATCH_RESULT(ctx) -#define BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(msg) -#define BOOST_SQLITE_CATCH_AND_RETURN() - -#else - -#define BOOST_SQLITE_TRY try -#define BOOST_SQLITE_CATCH_RESULT(ctx) \ -catch(boost::system::system_error & se) \ -{ \ - if (se.code().category() == boost::sqlite::sqlite_category()) \ - sqlite3_result_error_code(ctx, se.code().value()); \ - const auto msg = boost::sqlite::detail::get_message(se); \ - if (!msg.empty()) \ - sqlite3_result_error(ctx, msg.data(), msg.size()); \ -} \ -catch(std::bad_alloc &) { sqlite3_result_error_nomem(ctx); } \ -catch(std::length_error &) { sqlite3_result_error_toobig(ctx); } \ -catch(std::out_of_range &) { sqlite3_result_error_code(ctx, SQLITE_RANGE);} \ -catch(std::logic_error &le) \ -{ \ - sqlite3_result_error(ctx, le.what(), std::strlen(le.what())); \ - sqlite3_result_error_code(ctx, SQLITE_MISUSE); \ -} \ -catch(std::exception & ex) \ -{ \ - sqlite3_result_error(ctx, ex.what(), std::strlen(ex.what())); \ -} \ -catch(...) {sqlite3_result_error_code(ctx, SQLITE_ERROR); } - - -#define BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(msg) \ -catch (boost::system::system_error & se) \ -{ \ - auto code = SQLITE_ERROR; \ - if (se.code().category() == boost::sqlite::sqlite_category()) \ - code = se.code().value(); \ - const auto pre = boost::sqlite::detail::get_message(se); \ - msg = boost::sqlite::error_info(pre).release(); \ - return code; \ -} \ -catch(std::bad_alloc &) { return SQLITE_NOMEM; } \ -catch(std::length_error &) { return SQLITE_TOOBIG; } \ -catch(std::out_of_range &) { return SQLITE_RANGE;} \ -catch(std::logic_error &le) \ -{ \ - msg = boost::sqlite::error_info(le.what()).release(); \ - return SQLITE_MISUSE; \ -} \ -catch(std::exception & ex) \ -{ \ - msg = boost::sqlite::error_info(ex.what()).release(); \ - return SQLITE_ERROR; \ -} \ -catch(...) {return SQLITE_ERROR; } \ - - -#define BOOST_SQLITE_CATCH_AND_RETURN() \ -catch (boost::system::system_error & se) \ -{ \ - auto code = SQLITE_ERROR; \ - if (se.code().category() == boost::sqlite::sqlite_category()) \ - code = se.code().value(); \ - return code; \ -} \ -catch(std::bad_alloc &) { return SQLITE_NOMEM; } \ -catch(std::length_error &) { return SQLITE_TOOBIG; } \ -catch(std::out_of_range &) { return SQLITE_RANGE;} \ -catch(std::logic_error &) { return SQLITE_MISUSE;} \ -catch(...) { return SQLITE_ERROR; } \ - -#endif - -#endif //BOOST_SQLITE_DETAIL_CATCH_HPP diff --git a/include/boost/sqlite/detail/config.hpp b/include/boost/sqlite/detail/config.hpp deleted file mode 100644 index 2126f60..0000000 --- a/include/boost/sqlite/detail/config.hpp +++ /dev/null @@ -1,83 +0,0 @@ -// -// Copyright (c) 2022 Klemens Morgenstern (klemens.morgenstern@gmx.net) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BOOST_SQLITE_DETAIL_CONFIG_HPP -#define BOOST_SQLITE_DETAIL_CONFIG_HPP - -#include <boost/config.hpp> -#include <boost/core/detail/string_view.hpp> - -#if defined(BOOST_SQLITE_COMPILE_EXTENSION) -#include <sqlite3ext.h> -#define BOOST_SQLITE_COMPILING_EXTENSION 1 -#define BOOST_SQLITE_BEGIN_NAMESPACE namespace boost { namespace sqlite { inline namespace ext { -#define BOOST_SQLITE_END_NAMESPACE } } } -#else -#include <sqlite3.h> -#define BOOST_SQLITE_BEGIN_NAMESPACE namespace boost { namespace sqlite { -#define BOOST_SQLITE_END_NAMESPACE } } -#endif - -// copied from boost.json -#if defined(BOOST_SQLITE_DOCS) -# define BOOST_SQLITE_DECL -#else -# if (defined(BOOST_SQLITE_DYN_LINK) || defined(BOOST_ALL_DYN_LINK)) && !defined(BOOST_SQLITE_STATIC_LINK) -# if defined(BOOST_SQLITE_SOURCE) -# define BOOST_SQLITE_DECL BOOST_SYMBOL_EXPORT -# else -# define BOOST_SQLITE_DECL BOOST_SYMBOL_IMPORT -# endif -# endif // static lib -# ifndef BOOST_SQLITE_DECL -# define BOOST_SQLITE_DECL -# endif -# if !defined(BOOST_SQLITE_SOURCE) && !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_SQLITE_NO_LIB) -# define BOOST_LIB_NAME boost_sqlite -# if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_SQLITE_DYN_LINK) -# define BOOST_DYN_LINK -# endif -# include <boost/config/auto_link.hpp> -# endif -#endif - -BOOST_SQLITE_BEGIN_NAMESPACE - - -#if defined(BOOST_SQLITE_COMPILE_EXTENSION) -extern const sqlite3_api_routines *sqlite3_api; -#endif - -using string_view = boost::core::string_view; - -BOOST_SQLITE_END_NAMESPACE - -#define BOOST_SQLITE_RETURN_EC(ev) \ -do \ -{ \ - static constexpr auto loc##__LINE__((BOOST_CURRENT_LOCATION)); \ - return ::boost::system::error_code(ev, boost::sqlite::sqlite_category(), &loc##__LINE__); \ -} \ -while (false) - -#define BOOST_SQLITE_ASSIGN_EC(ec, ev) \ -do \ -{ \ - static constexpr auto loc##__LINE__((BOOST_CURRENT_LOCATION)); \ - ec.assign(ev, boost::sqlite::sqlite_category(), &loc##__LINE__); \ -} \ -while (false) - -#if defined(BOOST_SQLITE_NO_VIRTUAL) -#define BOOST_SQLITE_VIRTUAL -#define BOOST_SQLITE_PURE -#else -#define BOOST_SQLITE_VIRTUAL virtual -#define BOOST_SQLITE_PURE = 0 -#endif - -#endif // BOOST_SQLITE_DETAIL_HPP
\ No newline at end of file diff --git a/include/boost/sqlite/detail/exception.hpp b/include/boost/sqlite/detail/exception.hpp deleted file mode 100644 index 9f29cbe..0000000 --- a/include/boost/sqlite/detail/exception.hpp +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2023 Klemens D. Morgenstern -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_SQLITE_DETAIL_EXCEPTION_HPP -#define BOOST_SQLITE_DETAIL_EXCEPTION_HPP - -#include <boost/sqlite/detail/config.hpp> -#include <boost/sqlite/error.hpp> - -BOOST_SQLITE_BEGIN_NAMESPACE -namespace detail -{ - -BOOST_SQLITE_DECL -BOOST_NORETURN void throw_error_code(const boost::system::error_code & ec, - const boost::source_location & loc = BOOST_CURRENT_LOCATION); - -BOOST_SQLITE_DECL -BOOST_NORETURN void throw_error_code(const boost::system::error_code & ec, - const error_info & ei, - const boost::source_location & loc = BOOST_CURRENT_LOCATION); - -BOOST_SQLITE_DECL -BOOST_NORETURN void throw_out_of_range(const char * msg, - const boost::source_location & loc); - -BOOST_SQLITE_DECL -BOOST_NORETURN void throw_invalid_argument(const char * msg, - const boost::source_location & loc); - -inline core::string_view get_message(const system::system_error & se) -{ - auto ec_len = se.code().what().size(); - auto se_len = std::strlen(se.what()); - - if (ec_len == se_len) - return core::string_view(); - else - return core::string_view(se.what(), se_len - (ec_len + 2)); -} - - -} -BOOST_SQLITE_END_NAMESPACE - - -#endif //BOOST_SQLITE_DETAIL_EXCEPTION_HPP diff --git a/include/boost/sqlite/detail/scalar_function.hpp b/include/boost/sqlite/detail/scalar_function.hpp deleted file mode 100644 index ee16a23..0000000 --- a/include/boost/sqlite/detail/scalar_function.hpp +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright (c) 2023 Klemens D. Morgenstern -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_SQLITE_DETAIL_SCALAR_FUNCTION_HPP -#define BOOST_SQLITE_DETAIL_SCALAR_FUNCTION_HPP - -#include <boost/sqlite/detail/config.hpp> -#include <boost/sqlite/cstring_ref.hpp> -#include <boost/sqlite/memory.hpp> -#include <boost/sqlite/result.hpp> -#include <boost/sqlite/value.hpp> - -#include <boost/callable_traits/args.hpp> -#include <boost/callable_traits/return_type.hpp> -#include <boost/callable_traits/has_void_return.hpp> -#include <boost/core/span.hpp> - - -BOOST_SQLITE_BEGIN_NAMESPACE - -template<typename ... Args> -struct context; - -namespace detail -{ - -template<typename Func, typename ... Args, std::size_t Extent> -auto create_scalar_function_impl(sqlite3 * db, - cstring_ref name, - Func && func, - int flags, - std::tuple<context<Args...>, boost::span<value, Extent>> * , - std::false_type /* void return */, - std::false_type /* is pointer */) -> int -{ - using func_type = typename std::decay<Func>::type; - return sqlite3_create_function_v2( - db, name.c_str(), - Extent == boost::dynamic_extent ? -1 : static_cast<int>(Extent), - SQLITE_UTF8 | flags, - new (memory_tag{}) func_type(std::forward<Func>(func)), - +[](sqlite3_context* ctx, int len, sqlite3_value** args) - { - auto cc = context<Args...>(ctx); - auto aa = reinterpret_cast<value*>(args); - auto &f = *reinterpret_cast<func_type*>(sqlite3_user_data(ctx)); - boost::span<value, Extent> vals{aa, static_cast<std::size_t>(len)}; - - execute_context_function(ctx, f, cc, vals); - }, nullptr, nullptr, - +[](void * ptr) noexcept {delete_(static_cast<func_type*>(ptr));} - ); -} - -template<typename Func, typename ... Args, std::size_t Extent> -auto create_scalar_function_impl(sqlite3 * db, - cstring_ref name, - Func && func, int flags, - std::tuple<context<Args...>, boost::span<value, Extent>> * , - std::true_type /* void return */, - std::false_type /* is pointer */) -> int -{ - using func_type = typename std::decay<Func>::type; - return sqlite3_create_function_v2( - db, - name.c_str(), - (Extent == boost::dynamic_extent) ? -1 : static_cast<int>(Extent), - SQLITE_UTF8 | flags, - new (memory_tag{}) func_type(std::forward<Func>(func)), - +[](sqlite3_context* ctx, int len, sqlite3_value** args) - { - auto cc = context<Args...>(ctx); - auto aa = reinterpret_cast<value*>(args); - auto &f = *reinterpret_cast<func_type*>(sqlite3_user_data(ctx)); - boost::span<value, Extent> vals{aa, static_cast<std::size_t>(len)}; - - execute_context_function( - ctx, - [&]() - { - f(cc, vals); - return result<void>(); - }); - - }, nullptr, nullptr, - +[](void * ptr){delete_(static_cast<func_type*>(ptr));} - ); -} - - -template<typename Func, typename ... Args, std::size_t Extent> -auto create_scalar_function_impl(sqlite3 * db, - cstring_ref name, - Func * func, int flags, - std::tuple<context<Args...>, boost::span<value, Extent>> * , - std::false_type /* void return */, - std::true_type /* is pointer */) -> int -{ - return sqlite3_create_function_v2( - db, name.c_str(), - Extent == boost::dynamic_extent ? -1 : static_cast<int>(Extent), - SQLITE_UTF8 | flags, - reinterpret_cast<void*>(func), - +[](sqlite3_context* ctx, int len, sqlite3_value** args) - { - auto cc = context<Args...>(ctx); - auto aa = reinterpret_cast<value*>(args); - auto f = reinterpret_cast<Func*>(sqlite3_user_data(ctx)); - - boost::span<value, Extent> vals{aa, static_cast<std::size_t>(len)}; - - execute_context_function( - ctx, f, cc, vals); - }, nullptr, nullptr, nullptr); -} - -template<typename Func, typename ... Args, std::size_t Extent> -auto create_scalar_function_impl(sqlite3 * db, - cstring_ref name, - Func * func, int flags, - std::tuple<context<Args...>, boost::span<value, Extent>> * , - std::true_type /* void return */, - std::true_type /* is pointer */) -> int -{ - return sqlite3_create_function_v2( - db, - name.c_str(), - (Extent == boost::dynamic_extent) ? -1 : static_cast<int>(Extent), - SQLITE_UTF8 | flags, - reinterpret_cast<void*>(func), - +[](sqlite3_context* ctx, int len, sqlite3_value** args) - { - auto cc = context<Args...>(ctx); - auto aa = reinterpret_cast<value*>(args); - auto f = *reinterpret_cast<Func*>(sqlite3_user_data(ctx)); - boost::span<value, Extent> vals{aa, static_cast<std::size_t>(len)}; - execute_context_function( - ctx, - [&]() - { - f(cc, vals); - return result<void>(); - }); - - }, nullptr, nullptr, nullptr); -} - -template<typename Func> -auto create_scalar_function(sqlite3 * db, - cstring_ref name, - Func && func, - int flags) - -> decltype(create_scalar_function_impl( - db, name, std::forward<Func>(func), flags, - static_cast<callable_traits::args_t<Func>*>(nullptr), - callable_traits::has_void_return<Func>{}, - std::is_pointer<typename std::decay<Func>::type>{} - )) -{ - return create_scalar_function_impl(db, name, std::forward<Func>(func), flags, - static_cast<callable_traits::args_t<Func>*>(nullptr), - callable_traits::has_void_return<Func>{}, - std::is_pointer<typename std::decay<Func>::type>{}); -} - - -} - -BOOST_SQLITE_END_NAMESPACE - -#endif //BOOST_SQLITE_DETAIL_SCALAR_FUNCTION_HPP diff --git a/include/boost/sqlite/detail/vtable.hpp b/include/boost/sqlite/detail/vtable.hpp deleted file mode 100644 index f85f44c..0000000 --- a/include/boost/sqlite/detail/vtable.hpp +++ /dev/null @@ -1,611 +0,0 @@ -// Copyright (c) 2023 Klemens D. Morgenstern -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_SQLITE_DETAIL_VTABLE_HPP -#define BOOST_SQLITE_DETAIL_VTABLE_HPP - -#include <boost/sqlite/detail/config.hpp> -#include <boost/sqlite/detail/catch.hpp> -#include <boost/sqlite/vtable.hpp> - -BOOST_SQLITE_BEGIN_NAMESPACE -namespace detail -{ -struct vtab_impl -{ - -template<typename Module> -static int connect(sqlite3 * db, void * pAux, int argc, const char * const * argv, - sqlite3_vtab **ppVTab, char** errMsg) -{ - using table_type = typename Module::table_type; - auto &impl = *static_cast<Module*>(pAux); - BOOST_SQLITE_TRY - { - result<table_type> rtab = impl.connect( - sqlite::connection(db, false), - argc, argv); - - if (rtab.has_error()) - return extract_error(*errMsg, rtab); - - auto tab = make_unique<table_type>(std::move(*rtab)); - tab->db_ = db; - auto code = sqlite3_declare_vtab(db, tab->declaration()); - if (code != SQLITE_OK) - return code; - - sqlite::vtab::module_config cfg{db}; - auto r = tab->config(cfg); - if (r.has_error()) - return extract_error(*errMsg, r); - - *ppVTab = tab.release(); - - return SQLITE_OK; - } - BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(*errMsg) -} - - -template<typename Module> -static int create(sqlite3 * db, void * pAux, int argc, const char * const * argv, - sqlite3_vtab **ppVTab, char** errMsg) -{ - using table_type = typename Module::table_type; - auto &impl = *static_cast<Module*>(pAux); - BOOST_SQLITE_TRY - { - result<table_type> rtab = impl.create( - sqlite::connection(db, false), - argc, argv); - - if (rtab.has_error()) - return extract_error(*errMsg, rtab); - - auto tab = make_unique<table_type>(std::move(*rtab)); - tab->db_ = db; - - auto code = sqlite3_declare_vtab(db, tab->declaration()); - if (code != SQLITE_OK) - return code; - - sqlite::vtab::module_config mc{db}; - auto r = tab->config(mc); - if (r.has_error()) - return extract_error(*errMsg, r); - - *ppVTab = tab.release(); - - return SQLITE_OK; - } - BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(*errMsg) -} - -template<typename Table> -static int disconnect(sqlite3_vtab * tab) -{ - BOOST_SQLITE_TRY - { - auto tb = static_cast<Table*>(tab); - tb->~Table(); - sqlite3_free(tb); - return SQLITE_OK; - } - BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(tab->zErrMsg); -} - -template<typename Table> -static int destroy(sqlite3_vtab * tab) -{ - BOOST_SQLITE_TRY - { - auto tb = static_cast<Table*>(tab); - auto res = tb->destroy(); - tb->~Table(); - sqlite3_free(tb); - if (res.has_error()) - return std::move(res).error().code; - return SQLITE_OK; - } - BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(tab->zErrMsg); -} - -template<typename Module, typename Table> -static void assign_create(sqlite3_module & md, const Module &, - const sqlite::vtab::eponymous_module<Table> & base) -{ - md.xConnect = md.xCreate = &connect<Module>; - md.xDisconnect = md.xDestroy = &disconnect<Table>; - if (base.eponymous_only()) - md.xCreate = nullptr; -} - -template<typename Module, typename Table> -static void assign_create(sqlite3_module & md, const Module &, - const sqlite::vtab::module<Table> &) -{ - md.xConnect = &connect<Module>; - md.xDisconnect = &disconnect<Table>; - md.xCreate = &create<Module>; - md.xDestroy = &destroy<Table>; -} - -template<typename Table> -static int open(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor) -{ - auto tab = static_cast<Table *>(pVTab); - - BOOST_SQLITE_TRY - { - auto res = tab->open(); - if (res.has_error()) - return extract_error(pVTab->zErrMsg, res); - *ppCursor = new (memory_tag{}) typename Table::cursor_type(std::move(*res)); - return SQLITE_OK; - } - BOOST_SQLITE_CATCH_AND_RETURN(); -} - -template<typename Cursor> -static int close(sqlite3_vtab_cursor * cursor) -{ - auto p = static_cast<Cursor *>(cursor); - - BOOST_SQLITE_TRY - { - p->~Cursor(); - } - BOOST_SQLITE_CATCH_AND_RETURN(); - - sqlite3_free(p); - return SQLITE_OK; - -} - -template<typename Table> -static int best_index(sqlite3_vtab *pVTab, sqlite3_index_info* info) -{ - BOOST_SQLITE_TRY - { - auto tb = static_cast<Table*>(pVTab); - - sqlite::vtab::index_info ii(tb->db_, info); - auto r = tb->best_index(ii); - if (r.has_error()) - return extract_error(pVTab->zErrMsg, r); - - return SQLITE_OK; - } - BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVTab->zErrMsg); -} - - -template<typename Cursor> -static int filter(sqlite3_vtab_cursor* pCursor, - int idxNum, const char *idxStr, - int argc, sqlite3_value **argv) -{ - BOOST_SQLITE_TRY - { - auto cr = static_cast<Cursor*>(pCursor); - - auto r = cr->filter(idxNum, idxStr, - boost::span<value>{reinterpret_cast<value*>(argv), - static_cast<std::size_t>(argc)}); - if (r.has_error()) - return extract_error(pCursor->pVtab->zErrMsg, r); - - return SQLITE_OK; - } - BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pCursor->pVtab->zErrMsg); -} - - -template<typename Cursor> -static int next(sqlite3_vtab_cursor* pCursor) -{ - BOOST_SQLITE_TRY - { - auto cr = static_cast<Cursor*>(pCursor); - - auto r = cr->next(); - if (r.has_error()) - return extract_error(pCursor->pVtab->zErrMsg, r); - - return SQLITE_OK; - } - BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pCursor->pVtab->zErrMsg); -} - - -template<typename Cursor> -static int eof(sqlite3_vtab_cursor* pCursor) -{ - return static_cast<Cursor*>(pCursor)->eof() ? 1 : 0; -} - -template<typename Cursor> -static auto column(sqlite3_vtab_cursor* pCursor, - sqlite3_context * ctx, int idx) - -> typename std::enable_if<!std::is_void<typename Cursor::column_type>::value, int>::type -{ -#if SQLITE_VERSION_NUMBER >= 3032000 - bool no_change = sqlite3_vtab_nochange(ctx) != 0; -#else - bool no_change = false; -#endif - auto cr = static_cast<Cursor*>(pCursor); - execute_context_function( - ctx, - [&]{ - return cr->column(idx, no_change); - }); - - return SQLITE_OK; -} - - -template<typename Cursor> -static auto column(sqlite3_vtab_cursor* pCursor, - sqlite3_context * ctx, int idx) - -> typename std::enable_if<std::is_void<typename Cursor::column_type>::value, int>::type -{ -#if SQLITE_VERSION_NUMBER >= 3032000 - bool no_change = sqlite3_vtab_nochange(ctx) != 0; -#else - bool no_change = false; -#endif - auto cr = static_cast<Cursor*>(pCursor); - BOOST_SQLITE_TRY - { - cr->column(context<>{ctx}, idx, no_change); - } - BOOST_SQLITE_CATCH_RESULT(ctx); - return SQLITE_OK; -} - -template<typename Cursor> -static int row_id(sqlite3_vtab_cursor* pCursor, sqlite3_int64 *pRowid) -{ - BOOST_SQLITE_TRY - { - auto cr = static_cast<Cursor*>(pCursor); - - auto r = cr->row_id(); - if (r.has_error()) - return extract_error(pCursor->pVtab->zErrMsg, r); - *pRowid = *r; - return SQLITE_OK; - } - BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pCursor->pVtab->zErrMsg); -} - -template<typename Table> -static int update(sqlite3_vtab * pVTab, int argc, sqlite3_value ** argv, sqlite3_int64 * pRowid) -{ - using table_type = Table; - BOOST_SQLITE_TRY - { - auto & mod = *static_cast<table_type *>(pVTab); - auto db = mod.db_; - if (argc == 1 && sqlite3_value_type(argv[0]) != SQLITE_NULL) - { - auto r = mod.delete_(sqlite::value(*argv)); - if (r.has_error()) - return extract_error(pVTab->zErrMsg, r); - } - else if (argc > 1 && sqlite3_value_type(argv[0]) == SQLITE_NULL) - { - auto r = mod.insert(value{argv[1]}, - boost::span<value>{reinterpret_cast<value *>(argv + 2), - static_cast<std::size_t>(argc - 2)}, - sqlite3_vtab_on_conflict(db)); - if (r.has_error()) - return extract_error(pVTab->zErrMsg, r); - *pRowid = r.value(); - } - else if (argc > 1 && sqlite3_value_type(argv[0]) != SQLITE_NULL) - { - auto r = mod.update(sqlite::value(*argv), value{argv[1]}, // ID - boost::span<value>{reinterpret_cast<value *>(argv + 2), - static_cast<std::size_t>(argc - 2)}, - sqlite3_vtab_on_conflict(db)); - - if (r.has_error()) - return extract_error(pVTab->zErrMsg, r); - *pRowid = r.value(); - } - else - { - pVTab->zErrMsg = sqlite3_mprintf("Misuse of update api"); - return SQLITE_MISUSE; - } - - } - BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVTab->zErrMsg) - return SQLITE_OK; -} - -template<typename Module> -static void assign_update(sqlite3_module & md, const Module &, - std::true_type /* modifiable */) -{ - md.xUpdate = &update<typename Module::table_type>; -} - -template<typename Module> -static void assign_update(sqlite3_module & /*md*/, const Module &, - std::false_type /* modifiable */) -{ -} - -template<typename Table> -static int begin(sqlite3_vtab* pVTab) -{ - BOOST_SQLITE_TRY - { - auto cr = static_cast<Table*>(pVTab); - - auto r = cr->begin(); - if (r.has_error()) - return extract_error(pVTab->zErrMsg, r); - - return SQLITE_OK; - } - BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVTab->zErrMsg); -} - -template<typename Table> -static int sync(sqlite3_vtab* pVTab) -{ - BOOST_SQLITE_TRY - { - auto cr = static_cast<Table*>(pVTab); - - auto r = cr->sync(); - if (r.has_error()) - return extract_error(pVTab->zErrMsg, r); - - return SQLITE_OK; - } - BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVTab->zErrMsg); -} - -template<typename Table> -static int commit(sqlite3_vtab* pVTab) -{ - BOOST_SQLITE_TRY - { - auto cr = static_cast<Table*>(pVTab); - - auto r = cr->commit(); - if (r.has_error()) - return extract_error(pVTab->zErrMsg, r); - - return SQLITE_OK; - } - BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVTab->zErrMsg); -} - -template<typename Table> -static int rollback(sqlite3_vtab* pVTab) -{ - BOOST_SQLITE_TRY - { - auto cr = static_cast<Table*>(pVTab); - - auto r = cr->rollback(); - if (r.has_error()) - return extract_error(pVTab->zErrMsg, r); - - return SQLITE_OK; - } - BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVTab->zErrMsg); -} - -template<typename Module> -static void assign_transaction(sqlite3_module & /*md*/, const Module &, - std::false_type /* modifiable */) -{ -} - -template<typename Module> -static void assign_transaction(sqlite3_module & md, const Module &, - std::true_type /* modifiable */) -{ - md.xBegin = &begin <typename Module::table_type>; - md.xSync = &sync <typename Module::table_type>; - md.xCommit = &commit <typename Module::table_type>; - md.xRollback = &rollback<typename Module::table_type>; -} - -template<typename Table> -static int find_function(sqlite3_vtab *pVtab, int nArg, const char *zName, - void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), - void **ppArg) -{ - BOOST_SQLITE_TRY - { - auto cr = static_cast<Table*>(pVtab); - - auto r = cr->find_function( - nArg, zName, sqlite::vtab::function_setter(pxFunc, ppArg)); - if (r.has_error()) - return extract_error(pVtab->zErrMsg, r); - - return SQLITE_OK; - } - BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVtab->zErrMsg); -} - -template<typename Module> -static void assign_find_function(sqlite3_module & /*md*/, const Module &, - std::false_type /* overloadable */) -{ -} - -template<typename Module> -static void assign_find_function(sqlite3_module & md, const Module &, - std::true_type /* overloadable */) -{ - md.xFindFunction = &find_function<typename Module::table_type>; -} - -template<typename Table> -static int rename(sqlite3_vtab* pVTab, const char * name) -{ - BOOST_SQLITE_TRY - { - auto cr = static_cast<Table*>(pVTab); - - auto r = cr->rename(name); - if (r.has_error()) - return extract_error(pVTab->zErrMsg, r); - - return SQLITE_OK; - } - BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVTab->zErrMsg); -} - -template<typename Module> -static void assign_rename(sqlite3_module & /*md*/, const Module &, - std::false_type /* renamable */) -{ -} - -template<typename Module> -static void assign_rename(sqlite3_module & md, const Module &, - std::true_type /* renamable */) -{ - md.xRename = &rename<typename Module::table_type>; -} -#if SQLITE_VERSION_NUMBER >= 3007007 - -template<typename Table> -static int savepoint(sqlite3_vtab* pVTab, int i) -{ - BOOST_SQLITE_TRY - { - auto cr = static_cast<Table*>(pVTab); - - auto r = cr->savepoint(i); - if (r.has_error()) - return extract_error(pVTab->zErrMsg, r); - - return SQLITE_OK; - } - BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVTab->zErrMsg); -} - -template<typename Table> -static int release(sqlite3_vtab* pVTab, int i) -{ - BOOST_SQLITE_TRY - { - auto cr = static_cast<Table*>(pVTab); - - auto r = cr->release(i); - if (r.has_error()) - return extract_error(pVTab->zErrMsg, r); - - return SQLITE_OK; - } - BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVTab->zErrMsg); -} - -template<typename Table> -static int rollback_to(sqlite3_vtab* pVTab, int i) -{ - BOOST_SQLITE_TRY - { - auto cr = static_cast<Table*>(pVTab); - - auto r = cr->rollback_to(i); - if (r.has_error()) - return extract_error(pVTab->zErrMsg, r); - - return SQLITE_OK; - } - BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVTab->zErrMsg); -} - -template<typename Module> -static void assign_recursive_transaction(sqlite3_module & /*md*/, const Module &, - std::false_type /* recursive_transaction */) -{ -} - -template<typename Module> -static void assign_recursive_transaction(sqlite3_module & md, const Module &, - std::true_type /* recursive_transaction */) -{ - md.xSavepoint = &savepoint <typename Module::table_type>; - md.xRelease = &release <typename Module::table_type>; - md.xRollbackTo = &rollback_to<typename Module::table_type>; -} - -#endif - -#if SQLITE_VERSION_NUMBER >= 3026000 - -template<typename Table> -static void assign_shadow_name(sqlite3_module & /*md*/, const sqlite::vtab::module<Table> &) {} - -template<typename Table> -static void assign_shadow_name(sqlite3_module & /*md*/, const sqlite::vtab::eponymous_module<Table> &) {} - -template<typename Module, - bool (*Func)(const char *) = &Module::shadow_name> -static void assign_shadow_name(sqlite3_module & md, const Module & mod) -{ - md.xShadowName = +[](const char * name){return Func(name) != 0;}; -} - -#endif - -}; - -template<typename Module> -const sqlite3_module make_module(const Module & mod) -{ - sqlite3_module md; - std::memset(&md, 0, sizeof(sqlite3_module)); - -#if SQLITE_VERSION_NUMBER < 3007007 - md.iVersion = 1; -#elif SQLITE_VERSION_NUMBER < 3026000 - md.iVersion = 2; -#else - md.iVersion = 3; -#endif - using table_type = typename Module::table_type; - using cursor_type = typename table_type::cursor_type; - vtab_impl::assign_create(md, mod, mod); - md.xBestIndex = &vtab_impl::best_index<table_type>; - md.xOpen = &vtab_impl::open <table_type>; - md.xClose = &vtab_impl::close <cursor_type>; - md.xFilter = &vtab_impl::filter <cursor_type>; - md.xNext = &vtab_impl::next <cursor_type>; - md.xEof = &vtab_impl::eof <cursor_type>; - md.xColumn = &vtab_impl::column <cursor_type>; - md.xRowid = &vtab_impl::row_id <cursor_type>; - vtab_impl::assign_update (md, mod, std::is_base_of<sqlite::vtab::modifiable, table_type>{}); - vtab_impl::assign_transaction (md, mod, std::is_base_of<sqlite::vtab::transaction, table_type>{}); - vtab_impl::assign_find_function(md, mod, std::is_base_of<sqlite::vtab::overload_functions, table_type>{}); - vtab_impl::assign_rename (md, mod, std::is_base_of<sqlite::vtab::renamable, table_type>{}); -#if SQLITE_VERSION_NUMBER >= 3007007 - vtab_impl::assign_recursive_transaction(md, mod, std::is_base_of<sqlite::vtab::recursive_transaction, table_type>{}); -#endif -#if SQLITE_VERSION_NUMBER >= 3026000 - vtab_impl::assign_shadow_name(md, mod); -#endif - return md; -} - -} - -BOOST_SQLITE_END_NAMESPACE - -#endif //BOOST_SQLITE_DETAIL_VTABLE_HPP diff --git a/include/boost/sqlite/detail/window_function.hpp b/include/boost/sqlite/detail/window_function.hpp deleted file mode 100644 index df8475c..0000000 --- a/include/boost/sqlite/detail/window_function.hpp +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright (c) 2023 Klemens D. Morgenstern -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_SQLITE_IMPL_WINDOW_FUNCTION_HPP -#define BOOST_SQLITE_IMPL_WINDOW_FUNCTION_HPP -#if SQLITE_VERSION_NUMBER >= 3025000 - -#include <boost/sqlite/detail/config.hpp> -#include <boost/sqlite/cstring_ref.hpp> -#include <boost/sqlite/memory.hpp> -#include <boost/sqlite/result.hpp> -#include <boost/sqlite/value.hpp> - -BOOST_SQLITE_BEGIN_NAMESPACE - -namespace detail -{ - -template<typename Func> -struct window_function_maker -{ - void * mem; - - template<typename ... Args> - Func* operator()(Args && ... args) - { - return new (mem) Func(std::forward<Args>(args)...); - } -}; - -template<typename Func, typename Args> -int create_window_function(sqlite3 * db, cstring_ref name, Args && args, int flags, - std::true_type /* is void */) -{ - using args_type = callable_traits::args_t<decltype(&Func::step)>; - using span_type = typename std::tuple_element<1U, args_type>::type; - using func_type = typename std::decay<Func>::type; - using func_args_type = typename std::decay<Args>::type; - - return sqlite3_create_window_function( - db, name.c_str(), - span_type::extent == boost::dynamic_extent ? -1 : static_cast<int>(span_type::extent), - SQLITE_UTF8 | flags, - new (memory_tag{}) func_args_type(std::forward<Args>(args)), - +[](sqlite3_context* ctx, int len, sqlite3_value** args) noexcept //xStep - { - auto aa = reinterpret_cast<value*>(args); - auto fa = reinterpret_cast<func_args_type*>(sqlite3_user_data(ctx)); - auto c = static_cast<func_type*>(sqlite3_aggregate_context(ctx, 0)); - - execute_context_function( - ctx, - [&]() -> result<void> - { - if (c == nullptr) - { - auto p = sqlite3_aggregate_context(ctx, sizeof(func_type)); - if (!p) - return error(SQLITE_NOMEM); - c = mp11::tuple_apply(window_function_maker<func_type>{p}, *fa); - } - c->step(span_type{aa, static_cast<std::size_t>(len)}); - return {}; - }); - - }, - [](sqlite3_context* ctx) // xFinal - { - auto fa = reinterpret_cast<func_args_type*>(sqlite3_user_data(ctx)); - auto c = static_cast<func_type*>(sqlite3_aggregate_context(ctx, 0)); - - execute_context_function( - ctx, - [&]() -> result<decltype(c->value())> - { - if (c == nullptr) - { - auto p = sqlite3_aggregate_context(ctx, sizeof(func_type)); - if (!p) - return error(SQLITE_NOMEM); - c = mp11::tuple_apply(window_function_maker<func_type>{p}, *fa); - } - struct reaper {void operator()(func_type * c) { c->~func_type();}}; - std::unique_ptr<func_type, reaper> cl{c}; - - return c->value(); - }); - }, - [](sqlite3_context* ctx) //xValue - { - auto fa = reinterpret_cast<func_args_type*>(sqlite3_user_data(ctx)); - auto c = static_cast<func_type*>(sqlite3_aggregate_context(ctx, 0)); - execute_context_function( - ctx, - [&]() -> result<decltype(c->value())> - { - if (c == nullptr) - { - auto p = sqlite3_aggregate_context(ctx, sizeof(func_type)); - if (!p) - return error(SQLITE_NOMEM); - c = mp11::tuple_apply(window_function_maker<func_type>{p}, *fa); - } - return c->value(); - }); - - }, - +[](sqlite3_context* ctx, int len, sqlite3_value** args) // xInverse - { - auto aa = reinterpret_cast<value*>(args); - auto fa = reinterpret_cast<func_args_type*>(sqlite3_user_data(ctx)); - auto c = static_cast<func_type*>(sqlite3_aggregate_context(ctx, 0)); - execute_context_function( - ctx, - [&]() -> result<decltype(c->inverse(span_type{aa, static_cast<std::size_t>(len)}))> - { - if (c == nullptr) - { - auto p = sqlite3_aggregate_context(ctx, sizeof(func_type)); - if (!p) - return error(SQLITE_NOMEM); - c = mp11::tuple_apply(window_function_maker<func_type>{p}, *fa); - } - c->inverse(span_type{aa, static_cast<std::size_t>(len)}); - return {}; - }); - - }, - [](void * ptr) /* xDestroy */ { delete_(static_cast<func_type*>(ptr));} - ); -} - -template<typename Func, typename Args> -int create_window_function(sqlite3 * db, cstring_ref name, Args && args, int flags, - std::false_type /* is void */) -{ - using args_type = callable_traits::args_t<decltype(&Func::step)>; - using span_type = typename std::tuple_element<1U, args_type>::type; - using func_type = typename std::decay<Func>::type; - using func_args_type = typename std::decay<Args>::type; - - return sqlite3_create_window_function( - db, name.c_str(), - span_type::extent == boost::dynamic_extent ? -1 : static_cast<int>(span_type::extent), - SQLITE_UTF8 | flags, - new (memory_tag{}) func_args_type(std::forward<Args>(args)), - +[](sqlite3_context* ctx, int len, sqlite3_value** args) noexcept //xStep - { - auto aa = reinterpret_cast<value*>(args); - auto fa = reinterpret_cast<func_args_type*>(sqlite3_user_data(ctx)); - auto c = static_cast<func_type*>(sqlite3_aggregate_context(ctx, 0)); - - execute_context_function( - ctx, - [&]() -> result<decltype(c->step(span_type{aa, static_cast<std::size_t>(len)}))> - { - if (c == nullptr) - { - auto p = sqlite3_aggregate_context(ctx, sizeof(func_type)); - if (!p) - return {system::in_place_error, error(SQLITE_NOMEM)}; - c = mp11::tuple_apply(window_function_maker<func_type>{p}, *fa); - } - return c->step(span_type{aa, static_cast<std::size_t>(len)}); - }); - - }, - [](sqlite3_context* ctx) // xFinal - { - auto fa = reinterpret_cast<func_args_type*>(sqlite3_user_data(ctx)); - auto c = static_cast<func_type*>(sqlite3_aggregate_context(ctx, 0)); - execute_context_function( - ctx, - [&]() -> result<decltype(c->value())> - { - if (c == nullptr) - { - auto p = sqlite3_aggregate_context(ctx, sizeof(func_type)); - if (!p) - return {system::in_place_error, error(SQLITE_NOMEM)}; - c = mp11::tuple_apply(window_function_maker<func_type>{p}, *fa); - } - - struct reaper {void operator()(func_type * c) { c->~func_type();}}; - std::unique_ptr<func_type, reaper> cl{c}; - return c->value(); - }); - }, - [](sqlite3_context* ctx) //xValue - { - auto fa = reinterpret_cast<func_args_type*>(sqlite3_user_data(ctx)); - auto c = static_cast<func_type*>(sqlite3_aggregate_context(ctx, 0)); - execute_context_function( - ctx, - [&]() -> result<decltype(c->value())> - { - if (c == nullptr) - { - auto p = sqlite3_aggregate_context(ctx, sizeof(func_type)); - if (!p) - return {system::in_place_error, error(SQLITE_NOMEM)}; - c = mp11::tuple_apply(window_function_maker<func_type>{p}, *fa); - } - return c->value(); - }); - - }, - +[](sqlite3_context* ctx, int len, sqlite3_value** args) // xInverse - { - auto aa = reinterpret_cast<value*>(args); - auto fa = reinterpret_cast<func_args_type*>(sqlite3_user_data(ctx)); - auto c = static_cast<func_type*>(sqlite3_aggregate_context(ctx, 0)); - execute_context_function( - ctx, - [&]() -> result<decltype(c->inverse(span_type{aa, static_cast<std::size_t>(len)}))> - { - if (c == nullptr) - { - auto p = sqlite3_aggregate_context(ctx, sizeof(func_type)); - if (!p) - return {system::in_place_error, error(SQLITE_NOMEM)}; - c = mp11::tuple_apply(window_function_maker<func_type>{p}, *fa); - } - return c->inverse(span_type{aa, static_cast<std::size_t>(len)}); - }); - - }, - [](void * ptr) /* xDestroy */ { delete_(static_cast<func_type*>(ptr));} - ); -} - - -} - -BOOST_SQLITE_END_NAMESPACE -#endif // SQLITE_VERSION -#endif //BOOST_SQLITE_IMPL_WINDOW_FUNCTION_HPP diff --git a/include/boost/sqlite/error.hpp b/include/boost/sqlite/error.hpp deleted file mode 100644 index 9fe6211..0000000 --- a/include/boost/sqlite/error.hpp +++ /dev/null @@ -1,178 +0,0 @@ -// -// Copyright (c) 2022 Klemens Morgenstern (klemens.morgenstern@gmx.net) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BOOST_SQLITE_ERROR_HPP -#define BOOST_SQLITE_ERROR_HPP - -#include <boost/sqlite/detail/config.hpp> -#include <boost/sqlite/cstring_ref.hpp> -#include <boost/sqlite/memory.hpp> -#include <boost/system/error_code.hpp> -#include <boost/system/error_category.hpp> -#include <boost/system/result.hpp> - - -BOOST_SQLITE_BEGIN_NAMESPACE - -BOOST_SQLITE_DECL -system::error_category & sqlite_category(); - - -/** - * \brief Additional information about error conditions stored in an sqlite-allocate string - * \ingroup reference - * \details Contains an error message describing what happened. Not all error - * conditions are able to generate this extended information - those that - * can't have an empty error message. - */ -struct error_info -{ - /// Default constructor. - error_info() = default; - - /// Initialization constructor. - error_info(core::string_view msg) noexcept : msg_(new (memory_tag{}) char[msg.size() + 1u]) - { - std::memcpy(msg_.get(), msg.data(), (std::min)(msg.size() + 1, capacity())); - } - - /// set the message by copy - void set_message(core::string_view msg) - { - reserve(msg.size() + 1u); - std::memcpy(msg_.get(), msg.data(), (std::min)(msg.size() + 1, capacity())); - } - /// transfer ownership into the message - void reset(char * c = nullptr) - { - msg_.reset(c); - } - - /// use sqlite_mprintf to generate a message -#if defined(__GNUC__) - cstring_ref format(const char * fmt, ...) __attribute__((format (printf, 2, 3))) - { - va_list args; - va_start(args, fmt); - msg_.reset(sqlite3_vmprintf(fmt, args)); - va_end(args); - return msg_.get(); - } - -#endif - cstring_ref format(cstring_ref fmt, ...) - { - va_list args; - va_start(args, fmt); - msg_.reset(sqlite3_vmprintf(fmt.c_str(), args)); - va_end(args); - return msg_.get(); - } - - /// use sqlite_snprintf to generate a message -#if defined(__GNUC__) - cstring_ref snformat(const char * fmt, ...) __attribute__((format (printf, 2, 3))) - { - if (capacity() == 0) - return ""; - va_list args; - va_start(args, fmt); - sqlite3_vsnprintf(static_cast<int>(capacity()), msg_.get(), fmt, args); - va_end(args); - return msg_.get(); - } - -#endif - cstring_ref snformat(cstring_ref fmt, ...) - { - if (capacity() == 0) - return ""; - va_list args; - va_start(args, fmt); - sqlite3_vsnprintf(static_cast<int>(capacity()), msg_.get(), fmt.c_str(), args); - va_end(args); - return msg_.get(); - } - /// reserve data in the buffer i.e. allocate - void reserve(std::size_t sz) - { - if (msg_) - { - if (sqlite3_msize(msg_.get()) < sz) - msg_.reset(static_cast<char*>(sqlite3_realloc64(msg_.release(), sz))); - } - else - msg_.reset(static_cast<char*>(sqlite3_malloc64(sz))); - } - - /// Get the allocated memory - std::size_t capacity() const {return msg_ ? sqlite3_msize(msg_.get()) : 0u;} - - /// Gets the error message. - cstring_ref message() const noexcept { return msg_ ? msg_.get() : ""; } - - char * release() - { - return msg_.release(); - } - /// Restores the object to its initial state. - void clear() noexcept { if (msg_) *msg_ = '\0'; } - - - operator bool() const {return msg_.operator bool();} - private: - unique_ptr<char> msg_; -}; - - -/** - * \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; - - error(int code, error_info info) : code(code), info(std::move(info)) {} - explicit error(int code) : code(code) {} - error(int code, core::string_view info) - : code(code), - info(info) {} - - error(system::error_code code, error_info info) - : code(code.category() == sqlite_category() ? code.value() : SQLITE_FAIL), - info(std::move(info)) {} - - error(system::error_code code) : code(code.category() == sqlite_category() ? code.value() : SQLITE_FAIL) - { - if (code.category() == sqlite_category()) - info = error_info{code.what()}; - } - error() = default; - error(error && ) noexcept = default; -}; - -BOOST_NORETURN BOOST_SQLITE_DECL void throw_exception_from_error( error const & e, boost::source_location const & loc ); - -template<typename T = void> -using result = system::result<T, error>; - -template<typename T> -struct is_result_type : std::false_type {}; - -template<typename T> -struct is_result_type<result<T>> : std::true_type {}; - - -BOOST_SQLITE_END_NAMESPACE - - -#endif // BOOST_SQLITE_ERROR_HPP diff --git a/include/boost/sqlite/extension.hpp b/include/boost/sqlite/extension.hpp deleted file mode 100644 index 32553fa..0000000 --- a/include/boost/sqlite/extension.hpp +++ /dev/null @@ -1,67 +0,0 @@ -// -// Copyright (c) 2022 Klemens Morgenstern (klemens.morgenstern@gmx.net) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BOOST_SQLITE_EXTENSION_HPP -#define BOOST_SQLITE_EXTENSION_HPP - -#define BOOST_SQLITE_COMPILE_EXTENSION 1 -#include <boost/sqlite/detail/config.hpp> -#include <boost/sqlite/connection.hpp> -#include <boost/sqlite/detail/catch.hpp> -#include <boost/config.hpp> - - -/** @brief Declare a sqlite module. - @ingroup reference - - @param Name The name of the module - @param Conn The parameter name of the connection - - This macro can be used to create an sqlite extension. - - @note When defining BOOST_SQLITE_COMPILE_EXTENSION (was is done in extension.hpp) - sqlite will use an inline namespace to avoid symbol clashes. - - @par Examples - - @code{.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"); - }); - } - - @endcode{.cpp} - - */ -#define BOOST_SQLITE_EXTENSION(Name, Conn) \ -void sqlite_##Name##_impl (boost::sqlite::connection Conn); \ -extern "C" BOOST_SYMBOL_EXPORT \ -int sqlite3_##Name##_init( \ - sqlite3 *db, \ - char **pzErrMsg, \ - const sqlite3_api_routines *pApi) \ -{ \ - using boost::sqlite::sqlite3_api; \ - SQLITE_EXTENSION_INIT2(pApi); \ - \ - BOOST_SQLITE_TRY \ - { \ - sqlite_##Name##_impl(boost::sqlite::connection{db, false}); \ - return SQLITE_OK; \ - } \ - BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(*pzErrMsg); \ -} \ -void sqlite_##Name##_impl(boost::sqlite::connection Conn) - -#endif //BOOST_SQLITE_EXTENSION_HPP diff --git a/include/boost/sqlite/field.hpp b/include/boost/sqlite/field.hpp deleted file mode 100644 index 20fe4bd..0000000 --- a/include/boost/sqlite/field.hpp +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2022 Klemens D. Morgenstern -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_SQLITE_FIELD_HPP -#define BOOST_SQLITE_FIELD_HPP - -#include <boost/sqlite/detail/config.hpp> -#include <boost/sqlite/blob.hpp> -#include <boost/sqlite/cstring_ref.hpp> -#include <boost/sqlite/value.hpp> - -#include <boost/core/detail/string_view.hpp> - - -BOOST_SQLITE_BEGIN_NAMESPACE - -/** @brief A holder for a sqlite field, i.e. something returned from a query. - @ingroup reference - */ -struct field -{ - typedef sqlite_int64 int64; - - /// The type of the value - value_type type() const - { - return static_cast<value_type>( sqlite3_column_type(stm_, col_)); - } - /// Is the held value null - bool is_null() const - { - return type() == value_type::null; - } - /// Is the held value is not null - explicit operator bool () const - { - return type() != value_type::null; - } - /// Returns the value as an `int64`. - int64 get_int() const - { - return sqlite3_column_int64(stm_, col_); - } - /// Returns the value as an `double`. - double get_double() const - { - return sqlite3_column_double(stm_, col_); - } - /// Returns the value as text, i.e. a string_view. Note that this value may be invalidated`. - BOOST_SQLITE_DECL - cstring_ref get_text() const; - /// Returns the value as blob, i.e. raw memory. Note that this value may be invalidated`. - BOOST_SQLITE_DECL - blob_view get_blob() const; - /// Returns the field as a value. - value get_value() const - { - return value(sqlite3_column_value(stm_, col_)); - } - /// Returns the name of the column. - cstring_ref column_name() const - { - return sqlite3_column_name(stm_, col_); - } - /// Returns the name of the table. - cstring_ref table_name() const - { - return sqlite3_column_table_name(stm_, col_); - } - /// Returns the name of the original data source. - cstring_ref column_origin_name() const - { - return sqlite3_column_origin_name(stm_, col_); - } - - private: - friend struct row; - sqlite3_stmt * stm_; - int col_ = -1; -}; - -BOOST_SQLITE_END_NAMESPACE - -#endif //BOOST_SQLITE_FIELD_HPP diff --git a/include/boost/sqlite/function.hpp b/include/boost/sqlite/function.hpp deleted file mode 100644 index 14060b6..0000000 --- a/include/boost/sqlite/function.hpp +++ /dev/null @@ -1,452 +0,0 @@ -// -// Copyright (c) 2022 Klemens Morgenstern (klemens.morgenstern@gmx.net) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BOOST_SQLITE_FUNCTION_HPP -#define BOOST_SQLITE_FUNCTION_HPP - -#include <boost/sqlite/detail/config.hpp> -#include <boost/sqlite/detail/aggregate_function.hpp> -#include <boost/sqlite/detail/scalar_function.hpp> -#include <boost/sqlite/detail/window_function.hpp> -#include <boost/sqlite/connection.hpp> -#include <boost/sqlite/result.hpp> -#include <boost/sqlite/value.hpp> -#include <boost/sqlite/detail/exception.hpp> -#include <boost/sqlite/cstring_ref.hpp> - -#include <boost/core/span.hpp> -#include <boost/callable_traits/args.hpp> -#include <boost/callable_traits/has_void_return.hpp> -#include <boost/callable_traits/return_type.hpp> - -BOOST_SQLITE_BEGIN_NAMESPACE - -enum function_flags -{ - deterministic = SQLITE_DETERMINISTIC, - directonly = SQLITE_DIRECTONLY, - subtype = SQLITE_SUBTYPE, - innocuous = SQLITE_INNOCUOUS, - result_subtype = SQLITE_RESULT_SUBTYPE, -#if defined(SQLITE_SELFORDER1) - selforder1 = SQLITE_SELFORDER1, -#else - selforder1 = 0 -#endif -}; - - -/** @brief A context that can be passed into scalar functions. - @ingroup reference - - @tparam Args The argument that can be stored in the context. - - @code{.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; - }); - @endcode - -*/ -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) - { - sqlite3_set_auxdata(ctx_, Idx, *static_cast<void**>(&value), - new (memory_tag{}) element<Idx>(std::move(value)), - +[](void * ptr) - { - delete_(static_cast<element<Idx> *>(ptr)); - }); - } - - /// 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> & - { - using type = element<Idx> ; - auto p = static_cast<type*>(sqlite3_get_auxdata(ctx_, Idx)); - if (p == nullptr) - detail::throw_invalid_argument("argument not set", - BOOST_CURRENT_LOCATION); - return *p; - } - - /// 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> * - { - using type = element<Idx> ; - return static_cast<type*>(sqlite3_get_auxdata(ctx_, Idx)); - } - - - explicit context(sqlite3_context * ctx) noexcept : ctx_(ctx) {} - - /// Set the result through the context, instead of returning it. - template<typename T> - auto set_result(T && val) -#if !defined(BOOST_SQLITE_GENERATING_DOCS) - -> decltype(detail::set_result(static_cast<sqlite3_context*>(nullptr), std::forward<T>(val))) -#endif - { - detail::set_result(ctx_, std::forward<T>(val)); - } - /// Set the an error through the context, instead of throwing it. - void set_error(cstring_ref message, int code = SQLITE_ERROR) - { - sqlite3_result_error(ctx_, message.c_str(), -1); - sqlite3_result_error_code(ctx_, code); - } - /// Returns the connection of the context. - connection get_connection() const - { - return connection{sqlite3_context_db_handle(ctx_), false}; - } - - private: - sqlite3_context * ctx_; -}; - - -///@{ -/** @brief create a scalar function - @ingroup reference - - @param conn The connection to add the function to. - @param name The name of the function - @param func The function to be added - @param ec The system::error_code - - @throws `system::system_error` when the overload without `ec` is used. - - `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. - - @par Example - - @code{.cpp} - extern sqlite::connection conn; - - sqlite::create_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; - }); - @endcode - - */ -template<typename Func> -auto create_scalar_function( - connection & conn, - cstring_ref name, - Func && func, - function_flags flags, - system::error_code & ec, - error_info & ei) -#if !defined(BOOST_SQLITE_GENERATING_DOCS) - -> typename std::enable_if< - std::is_same< - decltype( - detail::create_scalar_function( - static_cast<sqlite3*>(nullptr), name, - std::declval<Func>(), flags) - ), int>::value>::type -#endif -{ - auto res = detail::create_scalar_function(conn.handle(), name, - std::forward<Func>(func), static_cast<int>(flags)); - if (res != 0) - { - BOOST_SQLITE_ASSIGN_EC(ec, res); - ei.set_message(sqlite3_errmsg(conn.handle())); - } -} - -///@{ -/** @brief create a scalar function - @ingroup reference - - @param conn The connection to add the function to. - @param name The name of the function - @param func The function to be added - @param ec The system::error_code - - @throws `system::system_error` when the overload without `ec` is used. - - `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. - - @par Example - - @code{.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; - }); - @endcode - - */ -template<typename Func> -auto create_scalar_function( - connection & conn, - cstring_ref name, - Func && func, - function_flags flags = {}) - -> typename std::enable_if< - std::is_same< - decltype( - detail::create_scalar_function( - static_cast<sqlite3*>(nullptr), name, - std::declval<Func>(), flags) - ), int>::value>::type -{ - system::error_code ec; - error_info ei; - create_scalar_function(conn, name, std::forward<Func>(func), flags, ec, ei); - if (ec) - detail::throw_error_code(ec, ei); -} -///@} - - -///@{ -/** @brief create a aggregate function - @ingroup reference - - @param conn The connection to add the function to. - @param name The name of the function - @param args - @param ec The system::error_code - -@tparam Func The function to be added - - @throws `system::system_error` when the overload without `ec` is used. - - - `func` needs to be an object with two functions: - - @code{.cpp} - void step(boost::span<sqlite::value, N> args); - T final(); - @endcode - - - - 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. - - @par Example - - @code{.cpp} - extern sqlite::connection conn; - - struct aggregate_func - { - aggregate_func(std::size_t init) : counter(init) {} - std::size_t counter; - void step(, boost::span<sqlite::value, 1u> val) - { - counter += val[0].get_text().size(); - } - - std::size_t final() - { - return counter; - } - }; - - sqlite::create_function<aggregate_func>( - conn, "char_counter", std::make_tuple(42)); - - @endcode - - */ -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) -{ - using func_type = typename std::decay<Func>::type; - auto res = detail::create_aggregate_function<Func>( - conn.handle(), name, std::forward<Args>(args), static_cast<int>(flags), - callable_traits::has_void_return<decltype(&func_type::step)>{} - ); - if (res != 0) - { - BOOST_SQLITE_ASSIGN_EC(ec, res); - ei.set_message(sqlite3_errmsg(conn.handle())); - } -} - -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; - create_aggregate_function<Func>(conn, name, std::forward<Args>(args), flags, ec, ei); - if (ec) - detail::throw_error_code(ec, ei); -} -///@} - -#if SQLITE_VERSION_NUMBER >= 3025000 - -///@{ -/** @brief create a aggregate window function - @ingroup reference - - @param conn The connection to add the function to. - @param name The name of the function - @param args The arguments to construct Func from. - @param ec The system::error_code - -@tparam Func The function to be added - - @throws `system::system_error` when the overload without `ec` is used. - - `func` needs to be an object with three functions: - - @code{.cpp} - void step(boost::span<sqlite::value, N> args); - void inverse(boost::span<sqlite::value, N> args); - T final(); - @endcode - - `State` can be any type and will get deduced together with `N`. - An aggregrate function will create a new `State` 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. - - @par Example - - @code{.cpp} - extern sqlite::connection conn; - - struct window_func - { - std::size_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::size_t final() - { - return counter; - } - }; - - sqlite::create_function( - conn, "win_char_counter", - aggregate_func{}); - @endcode - */ -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) -{ - using func_type = typename std::decay<Func>::type; - auto res = detail::create_window_function<Func>( - conn.handle(), name, std::forward<Args>(args), static_cast<int>(flags), - callable_traits::has_void_return<decltype(&func_type::step)>{}); - if (res != 0) - BOOST_SQLITE_ASSIGN_EC(ec, res); -} - -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; - create_window_function<Func>(conn, name, std::forward<Args>(args), flags, ec); - if (ec) - detail::throw_error_code(ec); -} - -///@} - -///@{ -/// Delete function - -inline void delete_function(connection & conn, cstring_ref name, int argc, system::error_code &ec) -{ - auto res = sqlite3_create_function_v2(conn.handle(), name.c_str(), argc, 0, nullptr, nullptr, nullptr, nullptr, nullptr); - if (res != 0) - BOOST_SQLITE_ASSIGN_EC(ec, res); - -} - -inline void delete_function(connection & conn, cstring_ref name, int argc = -1) -{ - system::error_code ec; - delete_function(conn, name, argc, ec); - if (ec) - detail::throw_error_code(ec); -} - -///@} -#endif - -BOOST_SQLITE_END_NAMESPACE - -#endif //BOOST_SQLITE_FUNCTION_HPP diff --git a/include/boost/sqlite/hooks.hpp b/include/boost/sqlite/hooks.hpp deleted file mode 100644 index 50cb4fc..0000000 --- a/include/boost/sqlite/hooks.hpp +++ /dev/null @@ -1,370 +0,0 @@ -// -// Copyright (c) 2022 Klemens Morgenstern (klemens.morgenstern@gmx.net) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BOOST_SQLITE_HOOKS_HPP -#define BOOST_SQLITE_HOOKS_HPP - -#include <boost/sqlite/detail/config.hpp> -#include <boost/sqlite/function.hpp> -#include <boost/system/result.hpp> - -BOOST_SQLITE_BEGIN_NAMESPACE - - -#if defined(SQLITE_ENABLE_PREUPDATE_HOOK) -/** The context for pre-update events - - @note This is only available if sqlite was compiled with `SQLITE_ENABLE_PREUPDATE_HOOK` enabled. - - */ -struct preupdate_context -{ - /// Returns the old value, i.e. the value before the update. - system::result<value> old(int column) const - { - sqlite3_value * val; - int res = sqlite3_preupdate_old(db_, column, &val); - if (res != 0) - BOOST_SQLITE_RETURN_EC(res); - return value(val); - } - /// The count of colums to be updated - int count() const { return sqlite3_preupdate_count(db_); } - /// The nesting depth of the update. - int depth() const { return sqlite3_preupdate_depth(db_); } - /// The new value to be written to column - system::result<value> new_(int column) const - { - sqlite3_value * val; - int res = sqlite3_preupdate_new(db_, column, &val); - if (res != 0) - BOOST_SQLITE_RETURN_EC(res); - return value(val); - } - - /// @brief Query the status of blob access, e.g. when using @ref blob_handle - /// @see https://www.sqlite.org/c3ref/preupdate_blobwrite.html - int blob_write() const { return sqlite3_preupdate_blobwrite(db_); } - - explicit preupdate_context(sqlite3 * db) noexcept : db_(db) {} - private: - sqlite3 * db_; -}; - -#endif - -namespace detail -{ - - -template<typename Func> -bool commit_hook_impl(sqlite3 * db, - Func * func, - std::true_type) -{ - static_assert(noexcept(func()), "hook must be noexcept"); - return sqlite3_commit_hook( db, func, [](void * data) { return (*static_cast<Func *>(data))() ? 1 : 0; }, nullptr) != nullptr; -} - - -template<typename Func> -bool commit_hook_impl(sqlite3 * db, - Func && func, - std::false_type) -{ - static_assert(noexcept(func()), "hook must be noexcept"); - return sqlite3_commit_hook( - db, - [](void * data) { return (*static_cast<Func *>(data))() ? 1 : 0; }, - &func) != nullptr; -} - -inline bool commit_hook(sqlite3 * db, std::nullptr_t, std::false_type) -{ - return sqlite3_commit_hook(db, nullptr, nullptr); -} - - - -template<typename Func> -bool commit_hook(sqlite3 * db, - Func && func) -{ - using func_type = typename std::decay<Func>::type; - return commit_hook_impl(db, std::forward<Func>(func), std::is_pointer<func_type>{}); -} - - - -template<typename Func> -bool rollback_hook_impl(sqlite3 * db, - Func * func, - std::true_type) -{ - static_assert(noexcept(func()), "hook must be noexcept"); - return sqlite3_rollback_hook( db, func, [](void * data) { (*static_cast<Func *>(data))(); }, nullptr) != nullptr; -} - - -template<typename Func> -bool rollback_hook_impl(sqlite3 * db, - Func && func, - std::false_type) -{ - static_assert(noexcept(func()), "hook must be noexcept"); - return sqlite3_rollback_hook( - db, - [](void * data) { (*static_cast<Func *>(data))(); }, - &func) != nullptr; -} - -inline bool rollback_hook_impl(sqlite3 * db, std::nullptr_t, std::false_type) -{ - return sqlite3_rollback_hook(db, nullptr, nullptr); -} - -template<typename Func> -bool rollback_hook(sqlite3 * db, - Func && func) -{ - using func_type = typename std::decay<Func>::type; - return rollback_hook_impl(db, std::forward<Func>(func), std::is_pointer<func_type>{}); -} - -#if defined(SQLITE_ENABLE_PREUPDATE_HOOK) - -template<typename Func> -bool preupdate_hook_impl(sqlite3 * db, - Func * func, - std::true_type) -{ - static_assert(noexcept(func(preupdate_context(nullptr), SQLITE_SELECT, "", "", 0, 0)), "hook must be noexcept"); - return sqlite3_preupdate_hook( - db, func, - [](void * data, - sqlite3* db, - int op, - const char * db_name, - const char * table_name, - sqlite_int64 key1, - sqlite_int64 key2) - { - (*static_cast<Func *>(data))(preupdate_context(db), op, db_name, table_name, key1, key2); - }, nullptr) != nullptr; -} - - -template<typename Func> -bool preupdate_hook_impl(sqlite3 * db, - Func & func, - std::false_type) -{ - static_assert(noexcept(func(preupdate_context(nullptr), SQLITE_SELECT, "", "", 0, 0)), - "hooks but be noexcept"); - using func_type = typename std::decay<Func>::type; - - return sqlite3_preupdate_hook( - db, - [](void * data, - sqlite3* db, - int op, - const char * db_name, - const char * table_name, - sqlite_int64 key1, - sqlite_int64 key2) - { - (*static_cast<Func *>(data))(preupdate_context(db), op, db_name, table_name, key1, key2); - }, &func) != nullptr; -} - -inline bool preupdate_hook_impl(sqlite3 * db, std::nullptr_t, std::false_type) -{ - return sqlite3_preupdate_hook(db, nullptr, nullptr); -} - -template<typename Func> -bool preupdate_hook(sqlite3 * db, - Func && func) -{ - using func_type = typename std::decay<Func>::type; - return preupdate_hook_impl(db, std::forward<Func>(func), std::is_pointer<func_type>{}); -} - -#endif - -template<typename Func> -bool update_hook_impl(sqlite3 * db, - Func * func, - std::true_type) -{ - static_assert(noexcept(func(SQLITE_SELECT, "", "", 0)), "hook must be noexcept"); - return sqlite3_update_hook( - db, func, - [](void * data, - sqlite3*, - int op, - const char * db, - const char * name, - sqlite_int64 key) - { - (*static_cast<Func *>(data))(op, db, name, key); - }, nullptr) != nullptr; -} - - -template<typename Func> -bool update_hook_impl(sqlite3 * db, - Func & func, - std::false_type) -{ - static_assert(noexcept(func(SQLITE_SELECT, "", "", 0)), "hook must be noexcept"); - using func_type = typename std::decay<Func>::type; - - return sqlite3_update_hook( - db, - [](void * data, - int op, - const char * db, - const char * name, - sqlite_int64 key) - { - (*static_cast<func_type*>(data))(op, db, name, key); - }, &func) != nullptr; -} - -inline -bool update_hook_impl(sqlite3 * db, - std::nullptr_t, - std::false_type) -{ - return sqlite3_update_hook(db, nullptr, nullptr); -} - -template<typename Func> -bool update_hook(sqlite3 * db, - Func && func) -{ - using func_type = typename std::decay<Func>::type; - return update_hook_impl(db, std::forward<Func>(func), std::is_pointer<func_type>{}); -} - - -} - -/** - @brief Install a commit hook - @ingroup reference - - @see [related sqlite documentation](https://www.sqlite.org/c3ref/commit_hook.html) - - The commit hook gets called before a commit gets performed. - 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. - - @param conn The database connection to install the hook in - @param func The hook function - @return true if an hook has been replaced. - */ -template<typename Func> -bool commit_hook(connection & conn, Func && func) -{ - return detail::commit_hook(conn.handle(), std::forward<Func>(func)); -} - -/** - @brief Install a rollback hook - @ingroup reference - - @see [related sqlite documentation](https://www.sqlite.org/c3ref/commit_hook.html) - - The rollback hook gets called when a rollback gets 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. - - @param conn The database connection to install the hook in - @param func The hook function - @return true if an hook has been replaced. - */ -template<typename Func> -bool rollback_hook(connection & conn, Func && func) -{ - return detail::rollback_hook(conn.handle(), std::forward<Func>(func)); -} - -#if defined(SQLITE_ENABLE_PREUPDATE_HOOK) -/** A hook for pre-update events. - - @note This is only available if sqlite was compiled with `SQLITE_ENABLE_PREUPDATE_HOOK` enabled. - @ingroup reference - - @see [related sqlite documentation](https://sqlite.org/c3ref/preupdate_count.html) - - The function will get called - - @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. - - @param conn The database connection to install the hook in - @param func The hook function - @return true if an hook has been replaced. - - The signature of the handler is as following (it must noexcept): - - @code{.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); - @endcode - - - -*/ -template<typename Func> -bool preupdate_hook(connection & conn, Func && func) -{ - return detail::preupdate_hook(conn.handle(), std::forward<Func>(func)); -} - -#endif - -/** - @brief Install an update hook - @ingroup reference - - @see [related sqlite documentation](https://www.sqlite.org/c3ref/update_hook.html) - - 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. - - 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`. - - @note If `func` is a `nullptr` the hook gets reset. - - @param conn The database connection to install the hook in - @param func The hook function - @return true if an hook has been replaced. - */ -template<typename Func> -bool update_hook(connection & conn, Func && func) -{ - return detail::update_hook(conn.handle(), std::forward<Func>(func)); -} - -BOOST_SQLITE_END_NAMESPACE - -#endif //BOOST_SQLITE_HOOKS_HPP diff --git a/include/boost/sqlite/json.hpp b/include/boost/sqlite/json.hpp deleted file mode 100644 index 3409e56..0000000 --- a/include/boost/sqlite/json.hpp +++ /dev/null @@ -1,140 +0,0 @@ -// -// Copyright (c) 2022 Klemens Morgenstern (klemens.morgenstern@gmx.net) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BOOST_SQLITE_JSON_HPP -#define BOOST_SQLITE_JSON_HPP - -#include <boost/sqlite/detail/config.hpp> -#include <boost/sqlite/field.hpp> -#include <boost/sqlite/resultset.hpp> -#include <boost/sqlite/value.hpp> -#include <boost/json/parse.hpp> -#include <boost/json/serializer.hpp> -#include <boost/json/storage_ptr.hpp> -#include <boost/json/value_from.hpp> - -BOOST_SQLITE_BEGIN_NAMESPACE - -struct resultset; -struct field; -struct value; - -/// @brief 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'); - -inline void tag_invoke(const struct set_result_tag &, sqlite3_context * ctx, const json::value & value) -{ - json::serializer ser; - ser.reset(&value); - - sqlite3_int64 len = 4096; - unique_ptr<char> c{static_cast<char*>(sqlite3_malloc64(len))}; - - len = sqlite3_msize(c.get()); - auto v = ser.read(c.get(), len); - - while (!ser.done()) - { - auto l = v.size(); - len *= 2; - c.reset(static_cast<char*>(sqlite3_realloc(c.release(), len))); - v = ser.read(c.get() + l, len); - } - - sqlite3_result_text(ctx, c.release(), v.size(), sqlite3_free); - sqlite3_result_subtype(ctx, json_subtype); -} - -///@{ -/// @brief Check if the value or field is a json. @ingroup reference -inline bool is_json(const value & v) { return v.type() == value_type::text && v.subtype() == json_subtype; } -inline bool is_json(const field & f) { return f.type() == value_type::text && f.get_value().subtype() == json_subtype; } -///@} - -///@{ -/// @brief Convert the value or field to a json. @ingroup reference -inline json::value as_json(const value & v, json::storage_ptr ptr = {}) -{ - return json::parse(v.get_text(), ptr); -} -inline json::value as_json(const field & f, json::storage_ptr ptr = {}) -{ - return json::parse(f.get_text(), ptr); -} -///@} - - -inline void tag_invoke( const json::value_from_tag &, json::value& val, const value & f) -{ - switch (f.type()) - { - case value_type::integer: - val.emplace_int64() = f.get_int(); - break; - case value_type::floating: - val.emplace_double() = f.get_double(); - break; - case value_type::text: - { - auto txt = f.get_text(); - if (f.subtype() == json_subtype) - val = json::parse(txt, val.storage()); - else - val.emplace_string() = txt; - } - break; - case value_type::blob: - throw_exception(std::invalid_argument("cannot convert blob to json")); - case value_type::null: - default: - val.emplace_null(); - } -} - -inline void tag_invoke( const json::value_from_tag &, json::value& val, const field & f) -{ - switch (f.type()) - { - case value_type::integer: - val.emplace_int64() = f.get_int(); - break; - case value_type::floating: - val.emplace_double() = f.get_double(); - break; - case value_type::text: - { - auto txt = f.get_text(); - if (f.get_value().subtype() == json_subtype) - val = json::parse(txt, val.storage()); - else - val.emplace_string() = txt; - } - break; - case value_type::blob: - throw_exception(std::invalid_argument("cannot convert blob to json")); - case value_type::null: - default: - val.emplace_null(); - } -} - -inline void tag_invoke( const json::value_from_tag &, json::value& val, resultset && rs) -{ - auto & obj = val.emplace_array(); - - for (auto r : rs) - { - auto & row = obj.emplace_back(json::object(obj.storage())).get_object(); - for (auto c : r) - row[c.column_name()] = json::value_from(c, row.storage()); - } -} - -BOOST_SQLITE_END_NAMESPACE - - -#endif //BOOST_SQLITE_JSON_HPP diff --git a/include/boost/sqlite/memory.hpp b/include/boost/sqlite/memory.hpp deleted file mode 100644 index e136a0e..0000000 --- a/include/boost/sqlite/memory.hpp +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright (c) 2023 Klemens D. Morgenstern -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_SQLITE_MEMORY_HPP -#define BOOST_SQLITE_MEMORY_HPP - -#include <boost/sqlite/detail/config.hpp> - -#include <memory> - -BOOST_SQLITE_BEGIN_NAMESPACE -/// A tag to allow `operator new` -/// @ingroup reference -struct memory_tag {}; -BOOST_SQLITE_END_NAMESPACE - - -inline void *operator new ( std::size_t size, boost::sqlite::memory_tag) noexcept -{ - using namespace boost::sqlite; - return sqlite3_malloc64(size); -} -inline void *operator new[]( std::size_t size, boost::sqlite::memory_tag) noexcept -{ - using namespace boost::sqlite; - return sqlite3_malloc64(size); -} - -inline void operator delete ( void* ptr, boost::sqlite::memory_tag) noexcept -{ - using namespace boost::sqlite; - return sqlite3_free(ptr); -} - -BOOST_SQLITE_BEGIN_NAMESPACE - -template<typename T> -void delete_(T * t) -{ - struct scoped_free - { - void * p; - ~scoped_free() - { - sqlite3_free(p); - } - }; - scoped_free _{t}; - t->~T(); -} - -namespace detail -{ - -template<typename T> -struct deleter -{ - void operator()(T* t) - { - delete_(t); - } -}; - -template<typename T> -struct deleter<T[]> -{ - static_assert(std::is_trivially_destructible<T>::value, "T[] needs to be trivially destructible"); - void operator()(T* t) - { - sqlite3_free(t); - } -}; - -template<> -struct deleter<void> -{ - void operator()(void* t) - { - sqlite3_free(t); - } -}; -} - -template<typename T> -using unique_ptr = std::unique_ptr<T, detail::deleter<T>>; - -template<typename T> -inline std::size_t msize(const unique_ptr<T> & ptr) -{ - return sqlite3_msize(ptr.get()); -} - -template<typename T, typename ... Args> -unique_ptr<T> make_unique(Args && ... args) -{ - unique_ptr<void> up{sqlite3_malloc64(sizeof(T))}; - unique_ptr<T> res{new (up.get()) T(std::forward<Args>(args)...)}; - up.release(); - return res; -} - -BOOST_SQLITE_END_NAMESPACE - -#endif //BOOST_SQLITE_MEMORY_HPP diff --git a/include/boost/sqlite/meta_data.hpp b/include/boost/sqlite/meta_data.hpp deleted file mode 100644 index 00f6527..0000000 --- a/include/boost/sqlite/meta_data.hpp +++ /dev/null @@ -1,58 +0,0 @@ -// -// Copyright (c) 2022 Klemens Morgenstern (klemens.morgenstern@gmx.net) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BOOST_SQLITE_META_DATA_HPP -#define BOOST_SQLITE_META_DATA_HPP - -#include <boost/sqlite/detail/config.hpp> -#include <boost/sqlite/connection.hpp> -#include <boost/sqlite/cstring_ref.hpp> - -BOOST_SQLITE_BEGIN_NAMESPACE - - -struct connection ; - -/// 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 -BOOST_SQLITE_DECL -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); -BOOST_SQLITE_DECL -column_meta_data table_column_meta_data(connection & conn, - cstring_ref table_name, cstring_ref column_name, - system::error_code & ec, error_info &ei); - -BOOST_SQLITE_DECL -column_meta_data table_column_meta_data(connection & conn, - cstring_ref db_name, cstring_ref table_name, cstring_ref column_name); -BOOST_SQLITE_DECL -column_meta_data table_column_meta_data(connection & conn, - cstring_ref table_name, cstring_ref column_name); -///@} - -/// -BOOST_SQLITE_END_NAMESPACE - - -#endif //BOOST_SQLITE_META_DATA_HPP diff --git a/include/boost/sqlite/mutex.hpp b/include/boost/sqlite/mutex.hpp deleted file mode 100644 index 63caf0e..0000000 --- a/include/boost/sqlite/mutex.hpp +++ /dev/null @@ -1,55 +0,0 @@ -// -// Copyright (c) 2022 Klemens Morgenstern (klemens.morgenstern@gmx.net) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BOOST_SQLITE_MUTEX_HPP -#define BOOST_SQLITE_MUTEX_HPP - -#include <boost/sqlite/detail/config.hpp> -#include <memory> - -BOOST_SQLITE_BEGIN_NAMESPACE -/// A mutex class that maybe a noop depending on the mode sqlite3 was compiled as. -struct mutex -{ - bool try_lock() - { - if (!impl_) - return false; - return sqlite3_mutex_try(impl_.get()) == SQLITE_OK; - } - void lock() { sqlite3_mutex_enter(impl_.get()); } - void unlock() { sqlite3_mutex_leave(impl_.get()); } - - mutex() : impl_(sqlite3_mutex_alloc(SQLITE_MUTEX_FAST)) {} - mutex(mutex && ) = delete; - private: - struct deleter_ {void operator()(sqlite3_mutex *mtx) {sqlite3_mutex_free(mtx);}}; - std::unique_ptr<sqlite3_mutex, deleter_> impl_; -}; - -/// A recursive mutex class that maybe a noop depending on the mode sqlite3 was compiled as. -struct recursive_mutex -{ - bool try_lock() - { - if (!impl_) - return false; - return sqlite3_mutex_try(impl_.get()) == SQLITE_OK; - } - void lock() { sqlite3_mutex_enter(impl_.get()); } - void unlock() { sqlite3_mutex_leave(impl_.get()); } - - recursive_mutex() : impl_(sqlite3_mutex_alloc(SQLITE_MUTEX_RECURSIVE)) {} - recursive_mutex(recursive_mutex && ) = delete; - private: - struct deleter_ {void operator()(sqlite3_mutex *mtx) {sqlite3_mutex_free(mtx);}}; - std::unique_ptr<sqlite3_mutex, deleter_> impl_; -}; - -BOOST_SQLITE_END_NAMESPACE - -#endif //BOOST_SQLITE_MUTEX_HPP diff --git a/include/boost/sqlite/result.hpp b/include/boost/sqlite/result.hpp deleted file mode 100644 index b609eb4..0000000 --- a/include/boost/sqlite/result.hpp +++ /dev/null @@ -1,147 +0,0 @@ -// -// Copyright (c) 2022 Klemens Morgenstern (klemens.morgenstern@gmx.net) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BOOST_SQLITE_RESULT_HPP -#define BOOST_SQLITE_RESULT_HPP - -#include <boost/sqlite/blob.hpp> -#include <boost/sqlite/detail/config.hpp> -#include <boost/sqlite/value.hpp> - -#include <boost/variant2/variant.hpp> - -#include <type_traits> - - -BOOST_SQLITE_BEGIN_NAMESPACE - - -struct set_result_tag {}; - - -inline void tag_invoke(set_result_tag, sqlite3_context * ctx, blob b) -{ - auto sz = b.size(); - sqlite3_result_blob(ctx, std::move(b).release(), sz, &operator delete); -} - - -inline void tag_invoke(set_result_tag, sqlite3_context * ctx, zero_blob zb) -{ - sqlite3_result_zeroblob64(ctx, static_cast<sqlite3_uint64>(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) -{ - sqlite3_result_int64(ctx, static_cast<sqlite3_int64>(value)); -} - -template<typename = std::enable_if_t<!std::is_same<std::int64_t, sqlite3_int64>::value>> -inline void tag_invoke(set_result_tag, sqlite3_context * ctx, std::int64_t value) - -{ - sqlite3_result_int64(ctx, static_cast<sqlite3_int64>(value)); -} - -inline void tag_invoke(set_result_tag, sqlite3_context * ctx, std::nullptr_t) { sqlite3_result_null(ctx); } -inline void tag_invoke(set_result_tag, sqlite3_context * ctx, string_view str) -{ - sqlite3_result_text(ctx, str.data(), str.size(), SQLITE_TRANSIENT); -} -template<typename String> -inline auto tag_invoke(set_result_tag, sqlite3_context * ctx, String && str) - -> typename std::enable_if<std::is_convertible<String, string_view>::value>::type -{ - return tag_invoke(set_result_tag{}, ctx, string_view(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) -{ - sqlite3_result_value(ctx, val.handle()); -} - -struct set_variant_result -{ - sqlite3_context * ctx; - template<typename T> - void operator()(T && val) - { - tag_invoke(set_result_tag{}, ctx, std::forward<T>(val)); - } -}; - -template<typename ... Args> -inline void tag_invoke(set_result_tag, sqlite3_context * ctx, const variant2::variant<Args...> & var) -{ - visit(set_variant_result{ctx}, var); -} - -template<typename T> -inline void tag_invoke(set_result_tag, sqlite3_context * ctx, std::unique_ptr<T> ptr) -{ - sqlite3_result_pointer(ctx, ptr.release(), typeid(T).name(), +[](void * ptr){delete static_cast<T*>(ptr);}); -} - -template<typename T> -inline void tag_invoke(set_result_tag, sqlite3_context * ctx, std::unique_ptr<T, void(*)(T*)> ptr) -{ - sqlite3_result_pointer(ctx, ptr.release(), typeid(T).name(), static_cast<void(*)(void*)>(ptr.get_deleter())); -} - -template<typename T, typename Deleter> -inline auto tag_invoke(set_result_tag, sqlite3_context * ctx, std::unique_ptr<T, Deleter> ptr) - -> typename std::enable_if<std::is_empty<Deleter>::value && - std::is_default_constructible<Deleter>::value>::type -{ - sqlite3_result_pointer(ctx, ptr.release(), typeid(T).name(), +[](void * ptr){Deleter()(static_cast<T*>(ptr));}); -} - -inline void tag_invoke(set_result_tag, sqlite3_context * ctx, error err) -{ - if (err.info) - sqlite3_result_error(ctx, err.info.message().c_str(), -1); - sqlite3_result_error_code(ctx, err.code); -} - - -template<typename T> -inline void tag_invoke(set_result_tag tag, sqlite3_context * ctx, result<T> res) -{ - if (res.has_value()) - tag_invoke(tag, ctx, std::move(res).value()); - else - tag_invoke(tag, ctx, std::move(res).error()); -} - -inline void tag_invoke(set_result_tag tag, sqlite3_context * ctx, result<void> res) -{ - if (res.has_error()) - tag_invoke(tag, ctx, std::move(res).error()); -} - - -namespace detail -{ - -template<typename Value> -inline auto set_result(sqlite3_context * ctx, Value && value) - -> decltype(tag_invoke(set_result_tag{}, ctx, std::forward<Value>(value))) -{ - tag_invoke(set_result_tag{}, ctx, std::forward<Value>(value)); -} - - -} - - -BOOST_SQLITE_END_NAMESPACE - -#endif //BOOST_SQLITE_RESULT_HPP diff --git a/include/boost/sqlite/resultset.hpp b/include/boost/sqlite/resultset.hpp deleted file mode 100644 index 7c514f0..0000000 --- a/include/boost/sqlite/resultset.hpp +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright (c) 2022 Klemens D. Morgenstern -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_SQLITE_RESULTSET_HPP -#define BOOST_SQLITE_RESULTSET_HPP - -#include <memory> -#include <boost/sqlite/row.hpp> -#include <boost/describe/members.hpp> - -#include <boost/system/result.hpp> - -BOOST_SQLITE_BEGIN_NAMESPACE -struct connection ; -/** - @brief Representation of a result from a database. - @ingroup reference - - If is a forward-range with output iterators. - - @par Example - - @code{.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 - - - @endcode - -*/ -struct resultset -{ - /// Returns the current row. - row current() const & - { - row r; - r.stm_ = impl_.get(); - return r; - } - /// Checks if the last row has been reached. - bool done() const {return done_;} - - ///@{ - /// Read the next row. Returns false if there's nothing more to read. - BOOST_SQLITE_DECL bool read_next(system::error_code & ec, error_info & ei); - BOOST_SQLITE_DECL bool read_next(); - ///@} - - /// - std::size_t column_count() const - { - return sqlite3_column_count(impl_.get()); - } - /// Returns the name of the column idx. - cstring_ref column_name(std::size_t idx) const - { - return sqlite3_column_name(impl_.get(), static_cast<int>(idx)); - } - /// Returns the name of the source table for column idx. - cstring_ref table_name(std::size_t idx) const - { - return sqlite3_column_table_name(impl_.get(), static_cast<int>(idx)); - } - /// Returns the origin name of the column for column idx. - cstring_ref column_origin_name(std::size_t idx) const - { - return sqlite3_column_origin_name(impl_.get(), static_cast<int>(idx)); - } - - /// 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() {} - explicit iterator(sqlite3_stmt * stmt, bool sentinel) : sentinel_(sentinel ) - { - row_.stm_ = stmt; - } - - bool operator!=(iterator rhs) const - { - return sentinel_ != rhs.sentinel_; - } - - row &operator*() { return row_; } - row *operator->() { return &row_; } - - BOOST_SQLITE_DECL - iterator operator++(); - - iterator operator++(int) - { - auto l = *this; - ++(*this); - return l; - } - - private: - row row_; - bool sentinel_ = true; - }; - - /// Return an input iterator to the currently unread row - iterator begin() { return iterator(impl_.get(), done_);} - /// Sentinel iterator. - iterator end() { return iterator(impl_.get(), true); } - - private: - friend struct connection; - friend struct statement; - - struct deleter_ - { - constexpr deleter_() noexcept {} - bool delete_ = true; - void operator()(sqlite3_stmt * sm) - { - if (sqlite3_data_count(sm) > 0) - while ( sqlite3_step(sm) == SQLITE_ROW); - if (delete_) - sqlite3_finalize(sm); - else - { - sqlite3_clear_bindings(sm); - sqlite3_reset(sm); - } - - } - }; - std::unique_ptr<sqlite3_stmt, deleter_> impl_; - bool done_ = false; -}; - -BOOST_SQLITE_END_NAMESPACE - - -#endif //BOOST_SQLITE_RESULTSET_HPP diff --git a/include/boost/sqlite/row.hpp b/include/boost/sqlite/row.hpp deleted file mode 100644 index 6893f96..0000000 --- a/include/boost/sqlite/row.hpp +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright (c) 2022 Klemens D. Morgenstern -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_SQLITE_ROW_HPP -#define BOOST_SQLITE_ROW_HPP - -#include <boost/sqlite/field.hpp> - -BOOST_SQLITE_BEGIN_NAMESPACE - -/** @brief Representation of a row in a database. - @ingroup reference - - Is a random-access range. - - All values that are obtained by view are valid until the next row is read. - - */ -struct row -{ - /// The size of the row - std::size_t size() const - { - return sqlite3_column_count(stm_); - } - /// Returns the field at `idx`, @throws std::out_of_range - BOOST_SQLITE_DECL - field at(std::size_t idx) const; - /// Returns the field at `idx`. - field operator[](std::size_t idx) const - { - field f; - f.stm_ = stm_; - f.col_ = static_cast<int>(idx); - return f; - } - /// 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++() - { - f_.col_++; - return *this; - } - - const_iterator operator++(int) - { - auto last = *this; - ++(*this); - return last; - } - - const_iterator & operator--() - { - f_.col_--; - return *this; - } - - const_iterator operator--(int) - { - auto last = *this; - --(*this); - return last; - } - - field operator[](int i) const - { - auto f = f_; - f.col_ += i; - return f; - } - - const_iterator operator+(int i) const - { - auto r = *this; - r.f_.col_ += i; - return r; - } - - const_iterator operator-(int i) const - { - auto r = *this; - r.f_.col_ -= i; - return r; - } - - const_iterator & operator+=(int i) - { - f_.col_ += i; - return *this; - } - - const_iterator & operator-=(int i) - { - f_.col_ -= i; - return *this; - } - - const field & operator*() const - { - return f_; - } - - const field * operator->() const - { - return &f_; - } - - bool operator==(const const_iterator& other) const - { - return f_.col_ == other.f_.col_ - && f_.stm_ == other.f_.stm_; - } - - bool operator!=(const const_iterator& other) const - { - return f_.col_ != other.f_.col_ - || f_.stm_ != other.f_.stm_; - } - - bool operator<(const const_iterator& other) const - { - return f_.col_ < other.f_.col_ - && f_.stm_ < other.f_.stm_; - } - - bool operator>(const const_iterator& other) const - { - return f_.col_ > other.f_.col_ - && f_.stm_ > other.f_.stm_; - } - - const_iterator() = default; - private: - friend struct row; - field f_; - }; - /// Returns the begin of the column-range. - const_iterator begin() const - { - const_iterator ci; - ci.f_.col_ = 0; - ci.f_.stm_ = stm_; - return ci; - } - /// Returns the end of the column-range. - const_iterator end() const - { - const_iterator ci; - ci.f_.col_ = sqlite3_column_count(stm_); - ci.f_.stm_ = stm_; - return ci; - } - private: - friend struct resultset; - sqlite3_stmt * stm_; - -}; - -BOOST_SQLITE_END_NAMESPACE - -#endif //BOOST_SQLITE_ROW_HPP diff --git a/include/boost/sqlite/statement.hpp b/include/boost/sqlite/statement.hpp deleted file mode 100644 index b77bbe8..0000000 --- a/include/boost/sqlite/statement.hpp +++ /dev/null @@ -1,651 +0,0 @@ -// Copyright (c) 2022 Klemens D. Morgenstern -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_SQLITE_STATEMENT_HPP -#define BOOST_SQLITE_STATEMENT_HPP - -#include <boost/sqlite/detail/config.hpp> -#include <boost/sqlite/detail/exception.hpp> -#include <boost/sqlite/blob.hpp> -#include <boost/sqlite/resultset.hpp> - -#include <boost/mp11/algorithm.hpp> -#include <boost/core/ignore_unused.hpp> -#include <boost/variant2/variant.hpp> - - -#include <tuple> - -BOOST_SQLITE_BEGIN_NAMESPACE -struct connection; -template<typename, bool> -struct static_resultset; - -/// @brief A reference to a value to temporary bind for an execute statement. Most values are captures by reference. -/// @ingroup reference -struct param_ref -{ - /// Default construct a parameter, gives `null`. - param_ref() = default; - /// Bind null - param_ref(variant2::monostate) : impl_{variant2::in_place_type_t<variant2::monostate>{}} {} - /// Bind null - param_ref(std::nullptr_t) : impl_{variant2::in_place_type_t<variant2::monostate>{}} {} - /// Bind an integer. - template<typename I, - typename = typename std::enable_if<std::is_integral<I>::value>::type> - param_ref(I value) - { - BOOST_IF_CONSTEXPR ((sizeof(I) == sizeof(int) && std::is_unsigned<I>::value) - || (sizeof(I) > sizeof(int))) - impl_.emplace<sqlite3_int64>(static_cast<sqlite3_int64>(value)); - else - impl_.emplace<int>(static_cast<int>(value)); - } - /// Bind a blob. - param_ref(blob_view blob) : impl_(blob) { } - /// Bind a string. - param_ref(string_view text) : impl_(text) { } - - template<typename StringLike> - param_ref(StringLike && text, - typename std::enable_if<std::is_constructible<string_view, StringLike>::value>::type * = nullptr) - : impl_(variant2::in_place_type_t<string_view>{}, text) {} - - template<typename BlobLike> - param_ref(BlobLike && text, - typename std::enable_if< - !std::is_constructible<string_view, BlobLike>::value - && std::is_constructible<blob_view, BlobLike>::value>::type * = nullptr) - : impl_(variant2::in_place_type_t<blob_view>{}, 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) { } - -#if SQLITE_VERSION_NUMBER >= 3020000 - /// Bind pointer value to the parameter. @see https://www.sqlite.org/bindptr.html - template<typename T> - param_ref(std::unique_ptr<T> ptr) - : impl_(variant2::in_place_index_t<7>{}, - std::unique_ptr<void, void(*)(void*)>( - static_cast<void*>(ptr.release()), - +[](void * ptr){delete static_cast<T*>(ptr);}), - typeid(T).name()) - { - } - - /// Bind pointer value with a function as deleter to the parameter. @see https://www.sqlite.org/bindptr.html - template<typename T> - param_ref(std::unique_ptr<T, void(*)(T*)> ptr) - : impl_(variant2::in_place_index_t<7>{}, - std::unique_ptr<void, void(*)(void*)>( - static_cast<void*>(ptr.release()), - +[](void * ptr){delete static_cast<T*>(ptr);}), - typeid(T).name()) - { - } - - /// @brief Bind pointer value with a function custom deleter to the parameter. - /// The deleter needs to be default constructible. @see https://www.sqlite.org/bindptr.html - template<typename T, typename Deleter> - param_ref(std::unique_ptr<T, Deleter> ptr, - typename std::enable_if<std::is_empty<Deleter>::value && - std::is_default_constructible<Deleter>::value, int>::type * = nullptr) - : impl_(variant2::in_place_index_t<7>{}, - std::unique_ptr<void, void(*)(void*)>( - static_cast<void*>(ptr.release()), - +[](void * ptr){delete static_cast<T*>(ptr);}), - typeid(T).name()) - { - } -#endif - - /// Apply the param_ref to a statement. - int apply(sqlite3_stmt * stmt, int c) const - { - return variant2::visit(visitor{stmt, c}, impl_); - } - - private: - struct make_visitor - { - template<typename T> - auto operator()(T&& t) const -> typename std::enable_if<std::is_constructible<param_ref, T&&>::value, param_ref>::type - { - return param_ref(std::forward<T>(t)); - } - }; - - public: - /// Construct param_ref from a variant - template<typename T> - param_ref(T && t, - decltype(variant2::visit(make_visitor(), std::forward<T>(t))) * = nullptr) - : param_ref(variant2::visit(make_visitor(), std::forward<T>(t))) - {} - private: - - struct visitor - { - sqlite3_stmt * stmt; - int col; - - int operator()(variant2::monostate ) - { - return sqlite3_bind_null(stmt, col); - } - int operator()(int i ) - { - return sqlite3_bind_int(stmt, col, i); - } - int operator()(sqlite3_int64 i64 ) - { - return sqlite3_bind_int64(stmt, col, i64); - } - - int operator()(blob_view blob) - { - if (blob.size() > static_cast<std::size_t>(std::numeric_limits<int>::max())) - return sqlite3_bind_blob64(stmt, col, blob.data(), blob.size(), SQLITE_STATIC); - else - return sqlite3_bind_blob(stmt, col, blob.data(), static_cast<int>(blob.size()), SQLITE_STATIC); - } - - int operator()(string_view text) - { - if (text.size() > std::numeric_limits<int>::max()) - return sqlite3_bind_text64(stmt, col, text.data(), text.size(), SQLITE_STATIC, SQLITE_UTF8); - else - return sqlite3_bind_text(stmt, col, text.data(), static_cast<int>(text.size()), SQLITE_STATIC); - } - int operator()(double value) - { - return sqlite3_bind_double(stmt, col, value); - } - int operator()(zero_blob zb) - { - if (static_cast<std::size_t>(zb) > static_cast<std::size_t>(std::numeric_limits<int>::max())) - return sqlite3_bind_zeroblob64(stmt, col, static_cast<sqlite3_uint64>(zb)); - else - return sqlite3_bind_zeroblob(stmt, col, static_cast<int>(zb)); - } -#if SQLITE_VERSION_NUMBER >= 3020000 - int operator()(std::pair<std::unique_ptr<void, void(*)(void*)>, const char*> & p) - { - auto d =p.first.get_deleter(); - return sqlite3_bind_pointer(stmt, col, p.first.release(), p.second, d); - } -#endif - }; - - mutable // so we can use it with - variant2::variant<variant2::monostate, int, sqlite3_int64, - blob_view, string_view, double, zero_blob -#if SQLITE_VERSION_NUMBER >= 3020000 - , std::pair<std::unique_ptr<void, void(*)(void*)>, const char*> -#endif - > impl_; -}; - - -/** @brief A statement used for a prepared-statement. - @ingroup reference - - */ -struct statement -{ - ///@{ - /** @brief execute the prepared statement once. - - @param params The arguments to be passed to the prepared statement. This can be a map or a vector of param_ref. - @param ec The system::error_code used to deliver errors for the exception less overload. - @param info The error_info used to deliver errors for the exception less overload. - @return The resultset of the query. - - @code{.cpp} - extern sqlite::connection conn; - statement st = conn.prepare("select id from users where name = $1;"); - resultset q = std::move(st).execute(std::make_tuple("peter")); - @endcode - - */ - template <typename ArgRange = std::initializer_list<param_ref>> - resultset execute( - ArgRange && params, - system::error_code& ec, - error_info& info) && - { - bind_impl(std::forward<ArgRange>(params), ec, info); - resultset rs; - rs.impl_.reset(impl_.release()); - if (!ec) - rs.read_next(ec, info); - return rs; - } - - template <typename ArgRange = std::initializer_list<param_ref>> - resultset execute(ArgRange && params) && - { - system::error_code ec; - error_info ei; - auto tmp = std::move(*this).execute(std::forward<ArgRange>(params), ec, ei); - if (ec) - detail::throw_error_code(ec, ei); - return tmp; - } - - resultset execute( - std::initializer_list<std::pair<string_view, param_ref>> params, - system::error_code& ec, - error_info& info) && - { - bind_impl(std::move(params), ec, info); - resultset rs; - rs.impl_.reset(impl_.release()); - if (!ec) - rs.read_next(ec, info); - return rs; - } - - resultset execute(std::initializer_list<std::pair<string_view, param_ref>> params) && - { - system::error_code ec; - error_info ei; - auto tmp = std::move(*this).execute(std::move(params), ec, ei); - if (ec) - detail::throw_error_code(ec, ei); - return tmp; - } - - 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) && - { - static_resultset<T, Strict> tmp = std::move(*this).execute(std::forward<ArgRange>(params), ec, ei); - if (ec) - return {}; - tmp.check_columns_(ec, ei); - if (ec) - return {}; - - return tmp; - } - - 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; - auto tmp = std::move(*this).execute<T>(std::forward<ArgRange>(params), ec, ei); - if (ec) - throw_exception(system::system_error(ec, ei.message())); - return tmp; - } - - 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) && - { - static_resultset<T, Strict> tmp = std::move(*this).execute(std::move(params), ec, ei); - if (ec) - return {}; - tmp.check_columns_(ec, ei); - if (ec) - return {}; - - return tmp; - } - - 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; - auto tmp = std::move(*this).execute<T, Strict>(std::move(params), ec, ei); - if (ec) - throw_exception(system::system_error(ec, ei.message())); - return tmp; - } - - ///@} - - ///@{ - /** @brief execute the prepared statement and reset it afterwards. - - @warning The handle is shared between the statement & resultset. The statemens need to be kept alive. - - @param params The arguments to be passed to the prepared statement. This can be a map, a vector or a stuple of param_ref. - @param ec The system::error_code used to deliver errors for the exception less overload. - @param info The error_info used to deliver errors for the exception less overload. - @return The resultset of the query. - - @code{.cpp} - extern sqlite::connection conn; - statement st = conn.prepare("select id from users where name = $1;"); - resultset q = std::move(st).execute(std::make_tuple("peter")); - @endcode - - - - */ - template <typename ArgRange = std::initializer_list<param_ref>> - resultset execute( - ArgRange && params, - system::error_code& ec, - error_info& info) & - { - bind_impl(std::forward<ArgRange>(params), ec, info); - resultset rs; - rs.impl_.get_deleter().delete_ = false; - rs.impl_.reset(impl_.get()); - if (!ec) - rs.read_next(ec, info); - return rs; - } - - - template <typename ArgRange = std::initializer_list<param_ref>> - resultset execute(ArgRange && params) & - { - system::error_code ec; - error_info ei; - auto tmp = execute(std::forward<ArgRange>(params), ec, ei); - if (ec) - detail::throw_error_code(ec, ei); - return tmp; - } - - - resultset execute( - std::initializer_list<std::pair<string_view, param_ref>> params, - system::error_code& ec, - error_info& info) & - { - bind_impl(std::move(params), ec, info); - resultset rs; - rs.impl_.get_deleter().delete_ = false; - rs.impl_.reset(impl_.get()); - if (!ec) - rs.read_next(ec, info); - return rs; - } - - resultset execute(std::initializer_list<std::pair<string_view, param_ref>> params) & - { - system::error_code ec; - error_info ei; - auto tmp = execute(std::move(params), ec, ei); - if (ec) - detail::throw_error_code(ec, ei); - return tmp; - } - - 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) & - { - static_resultset<T, Strict> tmp = execute(std::forward<ArgRange>(params), ec, ei); - if (ec) - return {}; - tmp.check_columns_(ec, ei); - if (ec) - return {}; - - return tmp; - } - - 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; - auto tmp = execute<T, Strict>(std::forward<ArgRange>(params), ec, ei); - if (ec) - throw_exception(system::system_error(ec, ei.message())); - return tmp; - } - - 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) & - { - static_resultset<T, Strict> tmp = execute(std::move(params), ec, ei); - if (ec) - return {}; - tmp.check_columns_(ec, ei); - if (ec) - return {}; - - return tmp; - } - - 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; - auto tmp = execute<T, Strict>(std::move(params), ec, ei); - if (ec) - throw_exception(system::system_error(ec, ei.message())); - return tmp; - } - - ///@} - - - /// Returns the sql used to construct the prepared statement. - core::string_view sql() - { - return sqlite3_sql(impl_.get()); - } - -#if SQLITE_VERSION_NUMBER >= 3014000 - /// Returns the expanded sql used to construct the prepared statement. - core::string_view expanded_sql() - { - return sqlite3_expanded_sql(impl_.get()); - } -#endif - - /// Returns the expanded sql used to construct the prepared statement. -#ifdef SQLITE_ENABLE_NORMALIZE - core::string_view normalized_sql() - { - return sqlite3_normalized_sql(impl_.get()); - } -#endif - - /// Returns the declared type of the column - core::string_view declared_type(int id) const - { - return sqlite3_column_decltype(impl_.get(), id); - } - - private: - - template<typename ... Args> - void bind_impl(std::tuple<Args...> && vec, - system::error_code & ec, - error_info & ei) - { - const auto sz = sqlite3_bind_parameter_count(impl_.get()); - if (sizeof...(Args) < static_cast<std::size_t>(sz)) - { - BOOST_SQLITE_ASSIGN_EC(ec, SQLITE_ERROR); - ei.format("To few parameters provided. Needed %d got %ld", - sz, sizeof...(Args)); - return; - } - - int i = 1, ar = SQLITE_OK; - mp11::tuple_for_each(std::move(vec), - [&](param_ref pr) - { - if (ar == SQLITE_OK) - ar = pr.apply(impl_.get(), i++); - }); - if (ar != SQLITE_OK) - { - BOOST_SQLITE_ASSIGN_EC(ec, ar); - ei.set_message(sqlite3_errmsg(sqlite3_db_handle(impl_.get()))); - return; - } - } - - - template<typename ... Args> - void bind_impl(const std::tuple<Args...> & vec, - system::error_code & ec, - error_info & ei) - { - const auto sz = sqlite3_bind_parameter_count(impl_.get()); - if (static_cast<int>(sizeof...(Args)) < sz) - { - BOOST_SQLITE_ASSIGN_EC(ec, SQLITE_ERROR); - ei.format("To few parameters provided. Needed %d got %ld", - sz, sizeof...(Args)); - return; - } - - int i = 1, ar = SQLITE_OK; - mp11::tuple_for_each(std::move(vec), - [&](param_ref pr) - { - if (ar == SQLITE_OK) - ar = pr.apply(impl_.get(), i++); - }); - if (ar != SQLITE_OK) - { - BOOST_SQLITE_ASSIGN_EC(ec, ar); - ei.set_message(sqlite3_errmsg(sqlite3_db_handle(impl_.get()))); - return; - } - } - - template<typename ParamVector> - void bind_impl(ParamVector && vec, system::error_code & ec, error_info & ei, - typename std::enable_if<std::is_convertible< - typename std::decay<ParamVector>::type::value_type, param_ref>::value>::type * = nullptr) - { - const auto sz = sqlite3_bind_parameter_count(impl_.get()); - if (vec.size() < static_cast<std::size_t>(sz)) - { - BOOST_SQLITE_ASSIGN_EC(ec, SQLITE_ERROR); - ei.format("To few parameters provided. Needed %d got %ld", - sz, vec.size()); - } - int i = 1; - for (const param_ref & pr : std::forward<ParamVector>(vec)) - { - int ar = pr.apply(impl_.get(), i++); - if (ar != SQLITE_OK) - { - - BOOST_SQLITE_ASSIGN_EC(ec, ar); - ei.set_message(sqlite3_errmsg(sqlite3_db_handle(impl_.get()))); - return; - } - } - } - - template<typename ParamMap> - void bind_impl(ParamMap && vec, system::error_code & ec, error_info & ei, - typename std::enable_if< - std::is_convertible<typename std::decay<ParamMap>::type::key_type, string_view>::value && - std::is_convertible<typename std::decay<ParamMap>::type::mapped_type, param_ref>::value - >::type * = nullptr) - { - for (auto i = 1; i <= sqlite3_bind_parameter_count(impl_.get()); i ++) - { - auto c = sqlite3_bind_parameter_name(impl_.get(), i); - if (c == nullptr) - { - BOOST_SQLITE_ASSIGN_EC(ec, SQLITE_MISUSE); - ei.set_message("Parameter maps require all parameters to be named."); - return ; - } - auto itr = vec.find(c+1); - if (itr == vec.end()) - { - BOOST_SQLITE_ASSIGN_EC(ec, SQLITE_MISUSE); - ei.format("Can't find value for key '%s'", c+1); - return ; - } - int ar = SQLITE_OK; - if (std::is_rvalue_reference<ParamMap&&>::value) - ar = param_ref(std::move(itr->second)).apply(impl_.get(), i); - else - ar = param_ref(itr->second).apply(impl_.get(), i); - - if (ar != SQLITE_OK) - { - - BOOST_SQLITE_ASSIGN_EC(ec, ar); - ei.set_message(sqlite3_errmsg(sqlite3_db_handle(impl_.get()))); - return; - } - } - } - - void bind_impl(std::initializer_list<std::pair<string_view, param_ref>> params, - system::error_code & ec, error_info & ei) - { - for (auto i = 1; i <= sqlite3_bind_parameter_count(impl_.get()); i ++) - { - auto c = sqlite3_bind_parameter_name(impl_.get(), i); - if (c == nullptr) - { - BOOST_SQLITE_ASSIGN_EC(ec, SQLITE_MISUSE); - ei.set_message("Parameter maps require all parameters to be named."); - return ; - } - - auto itr = std::find_if(params.begin(), params.end(), - [&](const std::pair<string_view, param_ref> & p) - { - return p.first == (c+1); - }); - if (itr == params.end()) - { - BOOST_SQLITE_ASSIGN_EC(ec, SQLITE_MISUSE); - ei.format("Can't find value for key '%s'", c+1); - return ; - } - auto ar = itr->second.apply(impl_.get(), i); - if (ar != SQLITE_OK) - { - - BOOST_SQLITE_ASSIGN_EC(ec, ar); - ei.set_message(sqlite3_errmsg(sqlite3_db_handle(impl_.get()))); - return; - } - } - } - - - friend - struct connection; - struct deleter_ - { - void operator()(sqlite3_stmt * sm) - { - sqlite3_finalize(sm); - } - }; - std::unique_ptr<sqlite3_stmt, deleter_> impl_; -}; - -BOOST_SQLITE_END_NAMESPACE - -#endif //BOOST_SQLITE_STATEMENT_HPP diff --git a/include/boost/sqlite/static_resultset.hpp b/include/boost/sqlite/static_resultset.hpp deleted file mode 100644 index fd6c359..0000000 --- a/include/boost/sqlite/static_resultset.hpp +++ /dev/null @@ -1,497 +0,0 @@ -// -// Copyright (c) 2024 Klemens Morgenstern (klemens.morgenstern@gmx.net) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BOOST_SQLITE_STATIC_RESULTSET_HPP -#define BOOST_SQLITE_STATIC_RESULTSET_HPP - -#include <boost/sqlite/detail/config.hpp> -#include <boost/sqlite/resultset.hpp> -#include <boost/sqlite/connection.hpp> - -#include <boost/describe/members.hpp> - -#include <array> -#include <cstdint> - -#if __cplusplus >= 202002L -#include <boost/pfr/core.hpp> -#include <boost/pfr/core_name.hpp> -#include <boost/pfr/traits.hpp> -#endif - - -namespace boost { template<typename> class optional;} - -#if __cplusplus >= 201702L -#include <optional> -#endif - -BOOST_SQLITE_BEGIN_NAMESPACE - -namespace detail -{ - -inline void convert_field(sqlite_int64 & target, const field & f) {target = f.get_int();} - -template<typename = std::enable_if_t<!std::is_same<std::int64_t, sqlite_int64>::value>> -inline void convert_field(std::int64_t & target, const field & f) -{ - target = static_cast<std::int64_t>(f.get_int()); -} - -inline void convert_field(double & target, const field & f) {target = f.get_double();} - - -template<typename Traits = std::char_traits<char>, typename Allocator = std::allocator<char>> -inline void convert_field(std::basic_string<char, Traits, Allocator> & target, const field & f) -{ - auto t = f.get_text(); - target.assign(t.begin(), t.end()); -} - -inline void convert_field(string_view & target, const field & f) {target = f.get_text();} -inline void convert_field(blob & target, const field & f) {target = blob(f.get_blob());} -inline void convert_field(blob_view & target, const field & f) {target = f.get_blob();} - -#if __cplusplus >= 201702L -template<typename T> -inline void convert_field(std::optional<T> & target, const field & f) -{ - if (f.is_null()) - target.reset(); - else - convert_field(target.emplace(), f); -} -#endif - -template<typename T> -inline void convert_field(boost::optional<T> & target, const field & f) -{ - if (f.is_null()) - target.reset(); - else - return convert_field(target.emplace_back(), f); -} - -template<typename T> -inline constexpr bool field_type_is_nullable(const T& ) {return false;} -#if __cplusplus >= 201702L -template<typename T> -inline bool field_type_is_nullable(const std::optional<T> &) { return true; } -#endif -template<typename T> -inline bool field_type_is_nullable(const boost::optional<T> &) { return true; } - -inline value_type required_field_type(const sqlite3_int64 &) {return value_type::integer;} - -template<typename = std::enable_if_t<!std::is_same<std::int64_t, sqlite_int64>::value>> -inline value_type required_field_type(const std::int64_t &) {return value_type::integer;} - -template<typename Allocator, typename Traits> -inline value_type required_field_type(const std::basic_string<char, Allocator, Traits> & ) -{ - return value_type::text; -} - -inline value_type required_field_type(const string_view &) {return value_type::text;} -inline value_type required_field_type(const blob &) {return value_type::blob;} -inline value_type required_field_type(const blob_view &) {return value_type::blob;} - - -template<typename ... Args> -void check_columns(const std::tuple<Args...> *, const resultset & r, - system::error_code &ec, error_info & ei) -{ - if (r.column_count() != sizeof...(Args)) - { - BOOST_SQLITE_ASSIGN_EC(ec, SQLITE_MISMATCH); - ei.format("Tuple size doesn't match column count [%ld != %ld]", sizeof...(Args), r.column_count()); - } -} - -template<bool Strict, typename ... Args> -void convert_row(std::tuple<Args...> & res, const row & r, system::error_code ec, error_info & ei) -{ - std::size_t idx = 0u; - - mp11::tuple_for_each( - res, - [&](auto & v) - { - const auto i = idx++; - const auto & f = r[i]; - BOOST_IF_CONSTEXPR (Strict) - { - if (!ec) // only check if we don't have an error yet. - { - if (f.is_null() && !field_type_is_nullable(v)) - { - BOOST_SQLITE_ASSIGN_EC(ec, SQLITE_CONSTRAINT_NOTNULL); - ei.format("unexpected null in column %d", i); - } - else if (f.type() != required_field_type(v)) - { - BOOST_SQLITE_ASSIGN_EC(ec, SQLITE_CONSTRAINT_DATATYPE); - ei.format("unexpected type [%s] in column %d, expected [%s]", - value_type_name(f.type()), i, value_type_name(required_field_type(v))); - } - } - } - else - boost::ignore_unused(ec, ei); - - detail::convert_field(v, f); - }); -} - -#if defined(BOOST_DESCRIBE_CXX14) - -template<typename T, typename = typename std::enable_if<describe::has_describe_members<T>::value>::type> -void check_columns(const T *, const resultset & r, - system::error_code &ec, error_info & ei) -{ - using mems = boost::describe::describe_members<T, describe::mod_public>; - constexpr std::size_t sz = mp11::mp_size<mems>(); - if (r.column_count() != sz) - { - BOOST_SQLITE_ASSIGN_EC(ec, SQLITE_MISMATCH); - ei.format("Describe size doesn't match column count [%ld != %ld]", sz, r.column_count()); - } - - // columns can be duplicated! - std::array<bool, sz> found; - std::fill(found.begin(), found.end(), false); - - for (std::size_t i = 0ul; i < r.column_count(); i++) - { - bool cfound = false; - boost::mp11::mp_for_each<mp11::mp_iota_c<sz>>( - [&](auto sz) - { - auto d = mp11::mp_at_c<mems, sz>(); - if (d.name == r.column_name(i)) - { - found[sz] = true; - cfound = true; - } - }); - - if (!cfound) - { - BOOST_SQLITE_ASSIGN_EC(ec, SQLITE_MISMATCH); - ei.format("Column '%s' not found in described struct.", r.column_name(i).c_str()); - break; - } - } - - if (ec) - return; - - - auto itr = std::find(found.begin(), found.end(), false); - if (itr != found.end()) - { - mp11::mp_with_index<sz>( - std::distance(found.begin(), itr), - [&](auto sz) - { - auto d = mp11::mp_at_c<mems, sz>(); - BOOST_SQLITE_ASSIGN_EC(ec, SQLITE_MISMATCH); - ei.format("Described field '%s' not found in resultset struct.", d.name); - }); - } -} - -template<bool Strict, typename T, - typename = typename std::enable_if<describe::has_describe_members<T>::value>::type> -void convert_row(T & res, const row & r, system::error_code ec, error_info & ei) -{ - for (auto && f: r) - { - boost::mp11::mp_for_each<boost::describe::describe_members<T, describe::mod_public> >( - [&](auto D) - { - if (D.name == f.column_name()) - { - auto & r = res.*D.pointer; - BOOST_IF_CONSTEXPR(Strict) - { - if (!ec) - { - if (f.is_null() && !field_type_is_nullable(r)) - { - BOOST_SQLITE_ASSIGN_EC(ec, SQLITE_CONSTRAINT_NOTNULL); - ei.format("unexpected null in column %s", D.name); - } - else if (f.type() != required_field_type(r)) - { - BOOST_SQLITE_ASSIGN_EC(ec, SQLITE_CONSTRAINT_DATATYPE); - ei.format("unexpected type [%s] in column %s, expected [%s]", - value_type_name(f.type()), D.name, value_type_name(required_field_type(r))); - } - } - } - - detail::convert_field(r, f); - } - }); - } -} - -#endif - -#if __cplusplus >= 202002L - -template<typename T> - requires (std::is_aggregate_v<T> && !describe::has_describe_members<T>::value) -void check_columns(const T *, const resultset & r, - system::error_code &ec, error_info & ei) -{ - constexpr std::size_t sz = pfr::tuple_size_v<T>; - if (r.column_count() != sz) - { - BOOST_SQLITE_ASSIGN_EC(ec, SQLITE_MISMATCH); - ei.format("Describe size doesn't match column count [%ld != %ld]", sz, r.column_count()); - } - - // columns can be duplicated! - std::array<bool, sz> found; - std::fill(found.begin(), found.end(), false); - - for (std::size_t i = 0ul; i < r.column_count(); i++) - { - bool cfound = false; - boost::mp11::mp_for_each<mp11::mp_iota_c<sz>>( - [&](auto sz) - { - if (pfr::get_name<sz, T>() == r.column_name(i)) - { - found[sz] = true; - cfound = true; - } - }); - - if (!cfound) - { - BOOST_SQLITE_ASSIGN_EC(ec, SQLITE_MISMATCH); - ei.format("Column %s not found in struct.", r.column_name(i).c_str()); - break; - } - } - - if (ec) - return; - - - auto itr = std::find(found.begin(), found.end(), false); - if (itr != found.end()) - { - mp11::mp_with_index<sz>( - std::distance(found.begin(), itr), - [&](auto sz) - { - BOOST_SQLITE_ASSIGN_EC(ec, SQLITE_MISMATCH); - auto nm = pfr::get_name<sz, T>(); - ei.format("PFR field %.*s not found in resultset struct.", static_cast<int>(nm.size()), nm.data()); - }); - } -} - -template<bool Strict, typename T> - requires (std::is_aggregate_v<T> && !describe::has_describe_members<T>::value) -void convert_row(T & res, const row & r, system::error_code ec, error_info & ei) -{ - for (auto && f: r) - { - boost::mp11::mp_for_each<mp11::mp_iota_c<pfr::tuple_size_v<T>>>( - [&](auto D) - { - if (pfr::get_name<D, T>() == f.column_name().c_str()) - { - auto & r = pfr::get<D()>(res); - BOOST_IF_CONSTEXPR(Strict) - { - if (!ec) - { - if (f.is_null() && !field_type_is_nullable(r)) - { - BOOST_SQLITE_ASSIGN_EC(ec, SQLITE_CONSTRAINT_NOTNULL); - ei.format("unexpected null in column %s", D.name); - } - else if (f.type() != required_field_type(r)) - { - BOOST_SQLITE_ASSIGN_EC(ec, SQLITE_CONSTRAINT_DATATYPE); - ei.format("unexpected type [%s] in column %s, expected [%s]", - value_type_name(f.type()), D.name, value_type_name(required_field_type(r))); - } - } - } - detail::convert_field(r, f); - } - }); - } -} - -#endif - -} - -/** - @brief A typed resultset using a tuple or a described struct. - @ingroup reference - @tparam T The static type of the query. - @tparam Strict Disables implicit conversions. - - If is a forward-range with output iterators. - - @par Example - - @code{.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 - - @endcode - -*/ -template<typename T, bool Strict > -struct static_resultset -{ - /// Returns the current row. - T current() const & - { - system::error_code ec; - error_info ei; - auto tmp = current(ec, ei); - if (ec) - throw_exception(system::system_error(ec, ei.message())); - return tmp; - } - - /// Returns the current row. - T current(system::error_code & ec, error_info & ei) const & - { - T res; - detail::convert_row<Strict>(res, result_.current(), ec, ei); - return res; - } - - /// 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. - BOOST_SQLITE_DECL bool read_next(system::error_code & ec, error_info & ei) { return result_.read_next(ec, ei); } - BOOST_SQLITE_DECL bool read_next() { return result_.read_next(); } - ///@} - - /// - std::size_t column_count() const { return result_.column_count(); } - /// Returns the name of the column idx. - core::string_view column_name(std::size_t idx) const { return result_.column_name(idx); } - - /// Returns the name of the source table for column idx. - core::string_view table_name(std::size_t idx) const { return result_.table_name(idx);} - /// Returns the origin name of the column for column idx. - core::string_view column_origin_name(std::size_t idx) const { return result_.column_origin_name(idx);} - - static_resultset() = default; - static_resultset(resultset && result) : result_(std::move(result)) { } - - - static_resultset(static_resultset<T, false> && rhs) : result_(std::move(rhs.result_)) {} - - /// 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) : itr_(itr) - { - system::error_code ec; - error_info ei; - if (itr->size() > 0ul) - detail::convert_row<Strict>(value_, *itr, ec, ei); - if (ec) - throw_exception(system::system_error(ec, ei.message())); - } - - bool operator!=(iterator rhs) const - { - return itr_ != rhs.itr_; - } - - value_type &operator*() { return value_; } - value_type *operator->() { return &value_; } - - iterator& operator++() - { - ++itr_; - - system::error_code ec; - error_info ei; - if (itr_->size() > 0ul) - detail::convert_row<Strict>(value_, *itr_, ec, ei); - if (ec) - throw_exception(system::system_error(ec, ei.message())); - - return *this; - } - iterator operator++(int) - { - auto l = *this; - ++(*this); - return l; - } - private: - resultset::iterator itr_; - value_type value_; - }; - - /// Return an input iterator to the currently unread row - iterator begin() { return iterator(result_.begin());} - /// Sentinel iterator. - iterator end() { return iterator(result_.end()); } - - - - static_resultset<T, true> strict() && - { - return {std::move(result_)}; - } - private: - - friend struct static_resultset<T, true>; - friend struct connection; - friend struct statement; - resultset result_; - void check_columns_( system::error_code & ec, error_info & ei) - { - detail::check_columns(static_cast<T*>(nullptr), result_, ec, ei); - } -}; - -BOOST_SQLITE_END_NAMESPACE - -#endif //BOOST_SQLITE_STATIC_RESULTSET_HPP diff --git a/include/boost/sqlite/string.hpp b/include/boost/sqlite/string.hpp deleted file mode 100644 index 5a81978..0000000 --- a/include/boost/sqlite/string.hpp +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2023 Klemens D. Morgenstern -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_SQLITE_STRING_HPP -#define BOOST_SQLITE_STRING_HPP - -#include <boost/sqlite/detail/config.hpp> -#include <boost/sqlite/cstring_ref.hpp> - -BOOST_SQLITE_BEGIN_NAMESPACE - -inline -bool like( - cstring_ref lhs, - cstring_ref rhs, - char escape = '\0') -{ - return sqlite3_strlike(lhs.c_str(), rhs.c_str(), escape) != 0; -} - -inline -bool glob( - cstring_ref lhs, - cstring_ref rhs) -{ - return sqlite3_strglob(lhs.c_str(), rhs.c_str()) != 0; -} - -inline -int icmp( - cstring_ref lhs, - cstring_ref rhs) -{ - return sqlite3_stricmp(lhs.c_str(), rhs.c_str()); -} - -inline -int icmp( - core::string_view lhs, - core::string_view rhs, - std::size_t n) -{ - return sqlite3_strnicmp(lhs.data(), rhs.data(), static_cast<int>(n)); -} - -BOOST_SQLITE_END_NAMESPACE - -#endif //BOOST_SQLITE_STRING_HPP diff --git a/include/boost/sqlite/transaction.hpp b/include/boost/sqlite/transaction.hpp deleted file mode 100644 index b90bdbf..0000000 --- a/include/boost/sqlite/transaction.hpp +++ /dev/null @@ -1,198 +0,0 @@ -// -// Copyright (c) 2024 Klemens Morgenstern (klemens.morgenstern@gmx.net) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BOOST_SQLITE_TRANSACTION_HPP -#define BOOST_SQLITE_TRANSACTION_HPP - -#include <boost/sqlite/connection.hpp> - -BOOST_SQLITE_BEGIN_NAMESPACE - -/** - * @brief A simple transaction guard implementing RAAI for transactions - * @ingroup reference - * - * @par Example - * @code{.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(); - * @endcode - */ -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) : conn_(conn), completed_(false) - { - } - - - /// Create transaction guard and initiate a transaction - transaction(connection & conn) : conn_(conn) - { - conn.execute("BEGIN"); - completed_ = false; - } - - /// Create transaction guard and initiate a transaction with the defined behaviour - transaction(connection & conn, behaviour b) : conn_(conn) - { - switch (b) - { - case deferred: conn.execute("BEGIN DEFERRED"); break; - case immediate: conn.execute("BEGIN IMMEDIATE"); break; - case exclusive: conn.execute("BEGIN EXCLUSIVE"); break; - } - completed_ = false; - } - - // see https://www.sqlite.org/lang_transaction.html re noexcept - /// rollback the transaction if not committed. - ~transaction() noexcept(SQLITE_VERSION_NUMBER >= 3007011) - { - if (!completed_) - conn_.execute("ROLLBACK"); - } - - ///@{ - /// Commit the transaction. - void commit() - { - conn_.execute("COMMIT"); - completed_ = true; - } - - void commit(system::error_code & ec, error_info & ei) - { - conn_.execute("COMMIT", ec, ei); - completed_ = true; - } - ///@} - - ///@{ - /// Rollback the transaction explicitly. - void rollback() - { - conn_.execute("ROLLBACK"); - completed_ = true; - } - - void rollback(system::error_code & ec, error_info & ei) - { - conn_.execute("ROLLBACK", ec, ei); - completed_ = true; - } - ///@} - - private: - connection & conn_; - bool completed_ = true; -}; - -/** - * @brief A simple transaction guard implementing RAAI for savepoints. Savepoints can be used recursively. - * @ingroup reference - * - * @par Example - * @code{.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(); - * @endcode -*/ -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) - : conn_(conn), name_(std::move(name)) - { - } - - /// Create transaction guard and initiate it - savepoint(connection & conn, std::string name) : conn_(conn), name_(std::move(name)) - { - conn.execute("SAVEPOINT " + name_); - completed_ = false; - } - - - /// rollback to the savepoint if not committed. - ~savepoint() noexcept(SQLITE_VERSION_NUMBER >= 3007011) - { - if (!completed_) - conn_.execute("ROLLBACK TO " + name_); - } - - ///@{ - /// Commit/Release the transaction. - void commit() - { - conn_.execute("RELEASE " + name_); - completed_ = true; - } - - void commit(system::error_code & ec, error_info & ei) - { - conn_.execute("RELEASE " + name_, ec, ei); - completed_ = true; - } - - void release() - { - conn_.execute("RELEASE " + name_); - completed_ = true; - } - - void release(system::error_code & ec, error_info & ei) - { - conn_.execute("RELEASE " + name_, ec, ei); - completed_ = true; - } - ///@} - - ///@{ - /// Rollback the transaction explicitly. - void rollback() - { - conn_.execute("ROLLBACK TO" + name_); - completed_ = true; - } - - void rollback(system::error_code & ec, error_info & ei) - { - conn_.execute("ROLLBACK TO " + name_, ec, ei); - completed_ = true; - } - ///@} - - /// The name of the savepoint. - const std::string & name() const {return name_;} - private: - connection & conn_; - std::string name_; - bool completed_ = true; -}; - - -BOOST_SQLITE_END_NAMESPACE - -#endif //BOOST_SQLITE_TRANSACTION_HPP diff --git a/include/boost/sqlite/value.hpp b/include/boost/sqlite/value.hpp deleted file mode 100644 index 16dc1c1..0000000 --- a/include/boost/sqlite/value.hpp +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright (c) 2022 Klemens D. Morgenstern -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_SQLITE_VALUE_HPP -#define BOOST_SQLITE_VALUE_HPP - -#include <boost/sqlite/detail/config.hpp> -#include <boost/sqlite/blob.hpp> -#include <boost/sqlite/cstring_ref.hpp> - - -BOOST_SQLITE_BEGIN_NAMESPACE - -/** @brief The type of a value - @ingroup reference - - [related sqlite documentation](https://www.sqlite.org/datatype3.html) -*/ -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, -}; - -inline -const char * value_type_name(value_type vt) -{ - switch (vt) - { - case value_type::text: return "text"; - case value_type::blob: return "blob"; - case value_type::floating: return "floating"; - case value_type::integer: return "integer"; - case value_type::null: return "null"; - default: return "unknown"; - } -} - - -/** @brief A holder for a sqlite values used for internal APIs - @ingroup reference - - */ -struct value -{ - // The value for integers in the database - typedef sqlite3_int64 int64 ; - - /// The type of the value - value_type type() const - { - return static_cast<value_type>(sqlite3_value_type(value_)); - } - /// The subtype of the value, see - int subtype() const - { - return sqlite3_value_subtype(value_); - } - /// Is the held value null - bool is_null() const - { - return type() == value_type::null; - } - /// Is the held value is not null - explicit operator bool () const - { - return type() != value_type::null; - } - /// Returns the value as an `integer`. - int64 get_int() const - { - return sqlite3_value_int64(value_); - } - /// Returns the value as an `double`. - double get_double() const - { - return sqlite3_value_double(value_); - } - /// Returns the value as text, i.e. a string_view. Note that this value may be invalidated`. - BOOST_SQLITE_DECL - cstring_ref get_text() const; - /// Returns the value as blob, i.e. raw memory. Note that this value may be invalidated`. - BOOST_SQLITE_DECL - blob_view get_blob() const; - - /// Best numeric datatype of the value - value_type numeric_type() const{return static_cast<value_type>(sqlite3_value_numeric_type(value_));} - -#if SQLITE_VERSION_NUMBER >= 3032000 - /// True if the column is unchanged in an UPDATE against a virtual table. - bool nochange() const {return 0 != sqlite3_value_nochange(value_);} -#endif - -#if SQLITE_VERSION_NUMBER >= 3031000 - /// True if value originated from a bound parameter - bool from_bind() const {return 0 != sqlite3_value_frombind(value_);} -#endif - /// 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 {return value_;} - handle_type & handle() {return value_;} - -#if SQLITE_VERSION_NUMBER >= 3020000 - /// Get a value that was passed through the pointer interface. - /// A value can be set as a pointer by binding/returning a unique_ptr. - template<typename T> - T * get_pointer() {return static_cast<T*>(sqlite3_value_pointer(value_, typeid(T).name()));} -#endif - private: - sqlite3_value * value_ = nullptr; -}; - -static_assert(sizeof(value) == sizeof(sqlite3_value*), "value must be same as sqlite3_value* pointer"); - -BOOST_SQLITE_END_NAMESPACE - -#endif //BOOST_SQLITE_VALUE_HPP diff --git a/include/boost/sqlite/vtable.hpp b/include/boost/sqlite/vtable.hpp deleted file mode 100644 index a984f4d..0000000 --- a/include/boost/sqlite/vtable.hpp +++ /dev/null @@ -1,615 +0,0 @@ -// -// Copyright (c) 2022 Klemens Morgenstern (klemens.morgenstern@gmx.net) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BOOST_SQLITE_VTABLE_HPP -#define BOOST_SQLITE_VTABLE_HPP - -#include <boost/sqlite/detail/config.hpp> -#include <boost/sqlite/detail/catch.hpp> -#include <boost/sqlite/function.hpp> - -#include <boost/core/span.hpp> -#include <boost/core/demangle.hpp> - -#include <bitset> - -BOOST_SQLITE_BEGIN_NAMESPACE -namespace detail -{ -struct vtab_impl; -} - - -namespace vtab -{ - -/// Helper type to set a function through the xFindFunction callback -struct function_setter -{ - /** Set the function - * - * @tparam Func The function type (either a lambda by ref or a pointer by copy) - * @param func The function to be used - * - * 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) - { - set_impl(func, static_cast<callable_traits::args_t<Func>*>(nullptr)); - } - - template<typename ... Args, std::size_t Extent> - void set(void(* ptr)(context<Args...>, span<value, Extent>)) noexcept - { - *ppArg_ = reinterpret_cast<void*>(ptr); - *pxFunc_ = - +[](sqlite3_context* ctx, int len, sqlite3_value** args) - { - auto cc = context<Args...>(ctx); - auto aa = reinterpret_cast<value*>(args); - auto &f = *reinterpret_cast<void(*)(context<Args...>, span<value, Extent>)>(sqlite3_user_data(ctx)); - detail::execute_context_function(ctx, f, cc, boost::span<value, Extent>{aa, static_cast<std::size_t>(len)}); - }; - } - - template<typename T, typename ... Args, std::size_t Extent> - void set(T(* ptr)(context<Args...>, span<value, Extent>)) - { - *ppArg_ = reinterpret_cast<void*>(ptr); - *pxFunc_ = - +[](sqlite3_context* ctx, int len, sqlite3_value** args) noexcept - { - auto cc = context<Args...>(ctx); - auto aa = reinterpret_cast<value*>(args); - auto &f = *reinterpret_cast<T(*)(context<Args...>, span<value, Extent>)>(sqlite3_user_data(ctx)); - detail::execute_context_function(ctx, f, cc, boost::span<value, Extent>{aa, static_cast<std::size_t>(len)}); - }; - } - - template<std::size_t Extent> - void set(void(* ptr)(span<value, Extent>)) - { - *ppArg_ = reinterpret_cast<void*>(ptr); - *pxFunc_ = - +[](sqlite3_context* ctx, int len, sqlite3_value** args) noexcept - { - auto aa = reinterpret_cast<value*>(args); - auto &f = *reinterpret_cast<void(*)(span<value, Extent>)>(sqlite3_user_data(ctx)); - detail::execute_context_function(ctx, f, boost::span<value, Extent>{aa, static_cast<std::size_t>(len)}); - }; - } - - template<typename T, std::size_t Extent> - void set(T(* ptr)(span<value, Extent>)) - { - *ppArg_ = reinterpret_cast<void*>(ptr); - *pxFunc_ = - +[](sqlite3_context* ctx, int len, sqlite3_value** args) noexcept - { - auto aa = reinterpret_cast<value*>(args); - auto &f = *reinterpret_cast<T(*)(span<value, Extent>)>(sqlite3_user_data(ctx)); - detail::execute_context_function(ctx, f, boost::span<value, Extent>{aa, static_cast<std::size_t>(len)}); - }; - } - - explicit function_setter(void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), - void **ppArg) : pxFunc_(pxFunc), ppArg_(ppArg) {} - private: - - template<typename Func, typename ... Args, std::size_t Extent> - void set_impl(Func & func, std::tuple<context<Args...>, span<value, Extent>>) - { - *ppArg_ = &func; - *pxFunc_ = - +[](sqlite3_context* ctx, int len, sqlite3_value** args) noexcept - { - auto cc = context<Args...>(ctx); - auto aa = reinterpret_cast<value*>(args); - auto &f = *reinterpret_cast<Func*>(sqlite3_user_data(ctx)); - detail::execute_context_function(ctx, f, cc, boost::span<value, Extent>{aa, static_cast<std::size_t>(len)}); - }; - } - template<typename Func, std::size_t Extent> - void set_impl(Func & func, std::tuple<span<value, Extent>> * ) - { - *ppArg_ = &func; - *pxFunc_ = - +[](sqlite3_context* ctx, int len, sqlite3_value** args) noexcept - { - auto aa = reinterpret_cast<value*>(args); - auto &f = *reinterpret_cast<Func *>(sqlite3_user_data(ctx)); - detail::execute_context_function(ctx, f, boost::span<value, Extent>{aa, static_cast<std::size_t>(len)}); - }; - } - - void (**pxFunc_)(sqlite3_context*,int,sqlite3_value**); - void **ppArg_; -}; - -#if SQLITE_VERSION_NUMBER >= 3038000 -/** @brief Utility function that can be used in `xFilter` for the `in` operator. - @see https://www.sqlite.org/capi3ref.html#sqlite3_vtab_in_first - @ingroup reference - @Note requires sqlite version >= 3.38 -*/ -struct in -{ - struct iterator - { - iterator() = default; - explicit iterator(sqlite3_value * value ) : value_(value) - { - if (value == nullptr) - return ; - auto res = sqlite3_vtab_in_first(value, &out_.handle()); - if (res != SQLITE_OK) - { - system::error_code ec; - BOOST_SQLITE_ASSIGN_EC(ec, res); - detail::throw_error_code(ec, ec.location()); - } - } - - iterator & operator++() - { - auto res = sqlite3_vtab_in_next(value_, &out_.handle()); - if (res != SQLITE_OK) - { - system::error_code ec; - BOOST_SQLITE_ASSIGN_EC(ec, res); - detail::throw_error_code(ec, ec.location()); - } - return *this; - } - - iterator operator++(int) - { - auto last = *this; - ++(*this); - return last; - } - - - const value & operator*() const - { - return out_; - } - - const value * operator->() const - { - return &out_; - } - - bool operator==(const iterator& other) const - { - return value_ == other.value_ - && out_.handle() == other.out_.handle(); - } - - bool operator!=(const iterator& other) const - { - return value_ != other.value_ - || out_.handle() != other.out_.handle(); - } - - - private: - sqlite3_value * value_{nullptr}; - value out_{nullptr}; - }; - - /// Returns a forward iterator to the `in` sequence for an `in` constraint pointing to the begin. - iterator begin() {return iterator(out_);} - /// Returns a forward iterator to the `in` sequence for an `in` constraint pointing to the end. - iterator end() {return iterator();} - - explicit in(sqlite3_value * out) : out_(out) {} - explicit in(sqlite::value out) : out_(out.handle()) {} - private: - sqlite3_value * out_{nullptr}; -}; - -#endif - -/// index info used by the find_index function -/// @ingroup reference -/// @see [sqlite reference](https://www.sqlite.org/vtab.html#xbestindex) -struct index_info -{ - /// Returns constraints of the index. - BOOST_ATTRIBUTE_NODISCARD - span<const sqlite3_index_info::sqlite3_index_constraint> constraints() const - { - return {info_->aConstraint, static_cast<std::size_t>(info_->nConstraint)}; - } - - /// Returns ordering of the index. - BOOST_ATTRIBUTE_NODISCARD - span<const sqlite3_index_info::sqlite3_index_orderby> order_by() const - { - return {info_->aOrderBy, static_cast<std::size_t>(info_->nOrderBy)}; - } - - BOOST_ATTRIBUTE_NODISCARD - span<sqlite3_index_info::sqlite3_index_constraint_usage> usage() - { - return {info_->aConstraintUsage, static_cast<std::size_t>(info_->nConstraint)}; - } - - BOOST_ATTRIBUTE_NODISCARD - sqlite3_index_info::sqlite3_index_constraint_usage & usage_of( - const sqlite3_index_info::sqlite3_index_constraint & info) - { - auto dist = std::distance(constraints().begin(), &info); - auto itr = usage().begin() + dist; - BOOST_ASSERT(itr < usage().end()); - return *itr; - } - -#if SQLITE_VERSION_NUMBER >= 3022000 - - /// Receive the collation for the contrainst of the position. - const char * collation(std::size_t idx) const - { - return sqlite3_vtab_collation(info_, static_cast<int>(idx)); - } -#endif - - int on_conflict() const {return sqlite3_vtab_on_conflict(db_);} - -#if SQLITE_VERSION_NUMBER >= 3038000 - /// Returns true if the constraint is - bool distinct() const {return sqlite3_vtab_distinct(info_);} - - value * rhs_value(std::size_t idx) const - { - value * v = nullptr; - if (sqlite3_vtab_rhs_value( - info_, static_cast<int>(idx), - reinterpret_cast<sqlite3_value**>(v)) == SQLITE_OK) - return v; - else - return nullptr; - } -#endif - - void set_already_ordered() { info_->orderByConsumed = 1; } - void set_estimated_cost(double cost) { info_->estimatedCost = cost; } -#if SQLITE_VERSION_NUMBER >= 3008200 - void set_estimated_rows(sqlite3_int64 rows) { info_->estimatedRows = rows; } -#endif -#if SQLITE_VERSION_NUMBER >= 3009000 - void set_index_scan_flags(int flags) { info_->idxFlags = flags; } -#endif -#if SQLITE_VERSION_NUMBER >= 3010000 - std::bitset<64u> columns_used() - { - return std::bitset<64u>(info_->colUsed); - } -#endif - - void set_index(int value) { info_->idxNum = value; } - void set_index_string(char * str, - bool take_ownership = true) - { - info_->idxStr = str; - info_->needToFreeIdxStr = take_ownership ? 1 : 0; - } - - sqlite3_index_info * info() const { return info_; } - sqlite3 * db() const { return db_; } - - private: - explicit index_info(sqlite3 * db, sqlite3_index_info * info) : db_(db), info_(info) {} - sqlite3 * db_; - sqlite3_index_info * info_{nullptr}; - friend struct detail::vtab_impl; -}; - - -struct module_config -{ -#if SQLITE_VERSION_NUMBER >= 3031000 - /// @brief Can be used to set SQLITE_VTAB_INNOCUOUS - void set_innocuous() - { - sqlite3_vtab_config(db_, SQLITE_VTAB_INNOCUOUS); - } - /// @brief Can be used to set SQLITE_VTAB_DIRECTONLY - void set_directonly() {sqlite3_vtab_config(db_, SQLITE_VTAB_DIRECTONLY);} - -#endif - - /// @brief Can be used to set SQLITE_VTAB_CONSTRAINT_SUPPORT - void set_constraint_support(bool enabled = false) - { - sqlite3_vtab_config(db_, SQLITE_VTAB_CONSTRAINT_SUPPORT, enabled ? 1 : 0); - } - - private: - explicit module_config(sqlite3 *db) : db_(db) {} - friend struct detail::vtab_impl; - sqlite3 *db_; -}; - -template<typename Table> -struct module -{ - using table_type = Table; - - /// @brief 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. - BOOST_SQLITE_VIRTUAL result<table_type> create(sqlite::connection db, int argc, const char * const argv[]) BOOST_SQLITE_PURE; - - /// @brief 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. - BOOST_SQLITE_VIRTUAL result<table_type> connect(sqlite::connection db, int argc, const char * const argv[]) BOOST_SQLITE_PURE; -}; - -template<typename Table> -struct eponymous_module -{ - using table_type = Table; - - /// @brief 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. - BOOST_SQLITE_VIRTUAL result<table_type> connect(sqlite::connection db, int argc, const char * const argv[]) BOOST_SQLITE_PURE; - - eponymous_module(bool eponymous_only = false) : eponymous_only_(eponymous_only) {} - - bool eponymous_only() const {return eponymous_only_;} - protected: - bool eponymous_only_{false}; - -}; - -template<typename ColumnType> -struct cursor; - -/// The basis for vtable -template<typename Cursor> -struct table : protected sqlite3_vtab -{ - using cursor_type = Cursor; - - BOOST_SQLITE_VIRTUAL result<void> config(module_config &) {return {};} - - /// The Table declaration to be used with sqlite3_declare_vtab - BOOST_SQLITE_VIRTUAL const char *declaration() BOOST_SQLITE_PURE; - - /// Destroy the storage = this function needs to be present for non eponymous tables - BOOST_SQLITE_VIRTUAL result<void> destroy() { return {}; } - - /// Tell sqlite how to communicate with the table. - /// Optional, this library will fill in a default function that leaves comparisons to sqlite. - BOOST_SQLITE_VIRTUAL result<void> best_index(index_info & /*info*/) {return {system::in_place_error, SQLITE_OK};} - - /// @brief 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. - BOOST_SQLITE_VIRTUAL result<cursor_type> open() BOOST_SQLITE_PURE; - - /// Get the connection of the vtable - sqlite::connection connection() const {return sqlite::connection{db_, false};} - - table(const sqlite::connection & conn) : db_(conn.handle()) {} - table(sqlite3 * db = nullptr) : db_(db) {} - private: - template<typename ColumnType> - friend struct cursor; - friend struct detail::vtab_impl; - - sqlite3 * db_{nullptr}; -}; - -/// Cursor needs the following member. @ingroup reference -template<typename ColumnType = void> -struct cursor : protected sqlite3_vtab_cursor -{ - using column_type = ColumnType; - - /// @brief Apply a filter to the cursor. Required when best_index is implemented. - BOOST_SQLITE_VIRTUAL result<void> filter( - int /*index*/, const char * /*index_data*/, - boost::span<sqlite::value> /*values*/) - { - return {system::in_place_error, SQLITE_OK}; - } - - /// @brief Returns the next row. - BOOST_SQLITE_VIRTUAL result<void> next() BOOST_SQLITE_PURE; - - /// @brief Check if the cursor is and the end - BOOST_SQLITE_VIRTUAL bool eof() BOOST_SQLITE_PURE; - - /// @brief Returns the result of a value. It will use the set_result functionality to create a an sqlite function. - /// see [vtab_no_change](https://www.sqlite.org/c3ref/vtab_nochange.html) - BOOST_SQLITE_VIRTUAL result<column_type> column(int idx, bool no_change) BOOST_SQLITE_PURE; - /// @brief Returns the id of the current row - BOOST_SQLITE_VIRTUAL result<sqlite3_int64> row_id() BOOST_SQLITE_PURE; - - /// Get the table the cursor is pointing to. - vtab::table<cursor> & table() { return *static_cast< vtab::table<cursor>*>(this->pVtab);} - const vtab::table<cursor> & table() const { return *static_cast<const vtab::table<cursor>*>(this->pVtab);} - - friend struct detail::vtab_impl; -}; - -/// Cursor needs the following member. @ingroup reference -template<> -struct cursor<void> : protected sqlite3_vtab_cursor -{ - using column_type = void; - - /// @brief Apply a filter to the cursor. Required when best_index is implemented. - BOOST_SQLITE_VIRTUAL result<void> filter( - int /*index*/, const char * /*index_data*/, - boost::span<sqlite::value> /*values*/) - { - return {system::in_place_error, SQLITE_OK}; - } - - /// @brief Returns the next row. - BOOST_SQLITE_VIRTUAL result<void> next() BOOST_SQLITE_PURE; - - /// @brief Check if the cursor is and the end - BOOST_SQLITE_VIRTUAL bool eof() BOOST_SQLITE_PURE; - - /// @brief Returns the result of a value. It will use the set_result functionality to create a an sqlite function. - /// see [vtab_no_change](https://www.sqlite.org/c3ref/vtab_nochange.html) - BOOST_SQLITE_VIRTUAL void column(context<> ctx, int idx, bool no_change) BOOST_SQLITE_PURE; - /// @brief Returns the id of the current row - BOOST_SQLITE_VIRTUAL result<sqlite3_int64> row_id() BOOST_SQLITE_PURE; - - /// Get the table the cursor is pointing to. - vtab::table<cursor> & table() { return *static_cast< vtab::table<cursor>*>(this->pVtab);} - const vtab::table<cursor> & table() const { return *static_cast<const vtab::table<cursor>*>(this->pVtab);} - - friend struct detail::vtab_impl; -}; - - -/// Group of functions for modifications. @ingroup reference -struct modifiable -{ - BOOST_SQLITE_VIRTUAL result<void> delete_(sqlite::value key) BOOST_SQLITE_PURE; - /// Insert a new row - BOOST_SQLITE_VIRTUAL result<sqlite_int64> insert(sqlite::value key, span<sqlite::value> values, int on_conflict) BOOST_SQLITE_PURE; - /// Update the row - BOOST_SQLITE_VIRTUAL result<sqlite_int64> update(sqlite::value old_key, sqlite::value new_key, span<sqlite::value> values, int on_conflict) BOOST_SQLITE_PURE; -}; - -/// Group of functions to support transactions. @ingroup reference -struct transaction -{ - /// Begin a tranasction - BOOST_SQLITE_VIRTUAL result<void> begin() BOOST_SQLITE_PURE; - /// synchronize the state - BOOST_SQLITE_VIRTUAL result<void> sync() BOOST_SQLITE_PURE; - /// commit the transaction - BOOST_SQLITE_VIRTUAL result<void> commit() BOOST_SQLITE_PURE; - /// rollback the transaction - BOOST_SQLITE_VIRTUAL result<void> rollback() BOOST_SQLITE_PURE; -}; - -/// Fucntion to enable function overriding See `xFindFunction`. -struct overload_functions -{ - /// @see https://www.sqlite.org/vtab.html#xfindfunction - BOOST_SQLITE_VIRTUAL result<void> find_function( - function_setter fs, - int arg, const char * name) BOOST_SQLITE_PURE; -}; - -/// Make the vtable renamable @ingroup reference -struct renamable -{ - /// Function to rename the table. Optional - BOOST_SQLITE_VIRTUAL result<void> rename(const char * new_name) BOOST_SQLITE_PURE; - -}; - -#if SQLITE_VERSION_NUMBER >= 3007007 -/// Support for recursive transactions @ingroup reference -struct recursive_transaction -{ - /// Save the current state with to `i` - BOOST_SQLITE_VIRTUAL result<void> savepoint(int i) BOOST_SQLITE_PURE; - /// Release all saves states down to `i` - BOOST_SQLITE_VIRTUAL result<void> release(int i) BOOST_SQLITE_PURE; - /// Roll the transaction back to `i`. - BOOST_SQLITE_VIRTUAL result<void> rollback_to(int i) BOOST_SQLITE_PURE; -}; -#endif - -} - - -namespace detail -{ - -template<typename Module> -const sqlite3_module make_module(const Module & mod); - -} - -////@{ -/** @brief Register a vtable - @ingroup reference - @see Sqlite vtab reference [vtab](https://www.sqlite.org/vtab.html) - - @param conn The connection to install the vtable into - @param name The name for the vtable - @param module The module to install as a vtable. See @ref vtab_module_prototype for the structure required - @param ec The system::error_code used to deliver errors for the exception less overload. - @param info The error_info used to deliver errors for the exception less overload. - - @param The requirements for `module`. - - @tparam T The implementation type of the module. It must inherit - - @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 & -{ - using module_type = typename std::decay<T>::type; - static const sqlite3_module mod = detail::make_module(module); - - std::unique_ptr<module_type> p{new (memory_tag{}) module_type(std::forward<T>(module))}; - auto pp = p.get(); - - int res = sqlite3_create_module_v2( - conn.handle(), name.c_str(), - &mod, p.release(), - +[](void * ptr) - { - static_cast<module_type*>(ptr)->~module_type(); - sqlite3_free(ptr); - }); - - if (res != SQLITE_OK) - { - BOOST_SQLITE_ASSIGN_EC(ec, res); - ei.set_message(sqlite3_errmsg(conn.handle())); - } - return *pp; -} - -template<typename T> -auto create_module(connection & conn, - const char * name, - T && module) -> typename std::decay<T>::type & -{ - system::error_code ec; - error_info ei; - T & ref = create_module(conn, name, std::forward<T>(module), ec, ei); - if (ec) - detail::throw_error_code(ec, ei); - return ref; -} -///@} - - -BOOST_SQLITE_END_NAMESPACE - -#include <boost/sqlite/detail/vtable.hpp> - -#endif //BOOST_SQLITE_VTABLE_HPP - |