// // 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 #include #include #include #include #include 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(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(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(sqlite3_realloc64(msg_.release(), sz))); } else msg_.reset(static_cast(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 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 using result = system::result; template struct is_result_type : std::false_type {}; template struct is_result_type> : std::true_type {}; BOOST_SQLITE_END_NAMESPACE #endif // BOOST_SQLITE_ERROR_HPP