From abf49b44cc47f39d6cceb83866f915bc03b7d900 Mon Sep 17 00:00:00 2001
From: Ferenc Szontágh <szf@fsociety.hu>
Date: Mon, 01 Jul 2024 18:08:34 +0000
Subject: [PATCH] reformat files
---
include/qtl_database_pool.hpp | 494
include/qtl_sqlite_pool.hpp | 53
include/qtl_common.hpp | 2655 ++++----
include/apply_tuple.h | 82
include/qtl_async.hpp | 560
include/qtl_postgres.hpp | 5347 ++++++++--------
include/qtl_asio.hpp | 549
include/qtl_sqlite.hpp | 2111 +++---
include/qtl_mysql_pool.hpp | 109
include/qtl_odbc.hpp | 3479 +++++-----
include/qtl_mysql.hpp | 3559 +++++-----
include/qtl_postgres_pool.hpp | 95
include/qtl_odbc_pool.hpp | 105
13 files changed, 9,693 insertions(+), 9,505 deletions(-)
diff --git a/include/apply_tuple.h b/include/apply_tuple.h
index b5a87c1..afa22fe 100644
--- a/include/apply_tuple.h
+++ b/include/apply_tuple.h
@@ -9,62 +9,58 @@
namespace qtl
{
-namespace detail
-{
+ namespace detail
+ {
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L)
-template <class F, class Tuple>
-inline constexpr decltype(auto) apply_tuple(F&& f, Tuple&& t)
-{
- return std::apply(std::forward<F>(f), std::forward<Tuple>(t));
-}
+ template <class F, class Tuple>
+ inline constexpr decltype(auto) apply_tuple(F &&f, Tuple &&t)
+ {
+ return std::apply(std::forward<F>(f), std::forward<Tuple>(t));
+ }
#else
-namespace detail
-{
- template<size_t N>
- struct apply
- {
- template<typename F, typename T, typename... A>
- static inline auto apply_tuple(F&& f, T&& t, A&&... a)
- -> decltype(apply<N-1>::apply_tuple(
- std::forward<F>(f), std::forward<T>(t),
- std::get<N-1>(std::forward<T>(t)), std::forward<A>(a)...
- ))
+ namespace detail
{
- return apply<N-1>::apply_tuple(std::forward<F>(f), std::forward<T>(t),
- std::get<N-1>(std::forward<T>(t)), std::forward<A>(a)...
- );
- }
- };
+ template <size_t N>
+ struct apply
+ {
+ template <typename F, typename T, typename... A>
+ static inline auto apply_tuple(F &&f, T &&t, A &&...a)
+ -> decltype(apply<N - 1>::apply_tuple(
+ std::forward<F>(f), std::forward<T>(t),
+ std::get<N - 1>(std::forward<T>(t)), std::forward<A>(a)...))
+ {
+ return apply<N - 1>::apply_tuple(std::forward<F>(f), std::forward<T>(t),
+ std::get<N - 1>(std::forward<T>(t)), std::forward<A>(a)...);
+ }
+ };
- template<>
- struct apply<0>
- {
- template<typename F, typename T, typename... A>
- static inline typename std::result_of<F(A...)>::type apply_tuple(F&& f, T&&, A&&... a)
+ template <>
+ struct apply<0>
+ {
+ template <typename F, typename T, typename... A>
+ static inline typename std::result_of<F(A...)>::type apply_tuple(F &&f, T &&, A &&...a)
+ {
+ return std::forward<F>(f)(std::forward<A>(a)...);
+ }
+ };
+ }
+
+ template <typename F, typename T>
+ inline auto apply_tuple(F &&f, T &&t)
+ -> decltype(detail::apply<std::tuple_size<
+ typename std::decay<T>::type>::value>::apply_tuple(std::forward<F>(f), std::forward<T>(t)))
{
- return std::forward<F>(f)(std::forward<A>(a)...);
+ return detail::apply<std::tuple_size<
+ typename std::decay<T>::type>::value>::apply_tuple(std::forward<F>(f), std::forward<T>(t));
}
- };
-}
-
-template<typename F, typename T>
-inline auto apply_tuple(F&& f, T&& t)
- -> decltype(detail::apply< std::tuple_size<
- typename std::decay<T>::type
- >::value>::apply_tuple(std::forward<F>(f), std::forward<T>(t)))
-{
- return detail::apply< std::tuple_size<
- typename std::decay<T>::type
- >::value>::apply_tuple(std::forward<F>(f), std::forward<T>(t));
-}
#endif // C++17
-}
+ }
}
diff --git a/include/qtl_asio.hpp b/include/qtl_asio.hpp
index 463a90a..0598428 100644
--- a/include/qtl_asio.hpp
+++ b/include/qtl_asio.hpp
@@ -4,8 +4,8 @@
#include "qtl_async.hpp"
#include <asio/version.hpp>
#define ASIO_STANDALONE
-#if defined(_MSC_VER) && _WIN32_WINNT<0x0600
-#define ASIO_ENABLE_CANCELIO 1
+#if defined(_MSC_VER) && _WIN32_WINNT < 0x0600
+#define ASIO_ENABLE_CANCELIO 1
#endif
#if ASIO_VERSION < 101200
#include <asio/io_service.hpp>
@@ -18,67 +18,68 @@
#include <asio/steady_timer.hpp>
#if ASIO_VERSION < 100000
-#error The asio version required by QTL is at least 10.0
+#error The asio version required by QTL is at least 10.0
#endif
namespace qtl
{
-namespace NS_ASIO = ::asio;
+ namespace NS_ASIO = ::asio;
-namespace asio
-{
+ namespace asio
+ {
-class service
-{
-public:
+ class service
+ {
+ public:
#if ASIO_VERSION < 101200
- typedef NS_ASIO::io_service service_type;
+ typedef NS_ASIO::io_service service_type;
#else
- typedef NS_ASIO::io_context service_type;
+ typedef NS_ASIO::io_context service_type;
#endif // ASIO_VERSION
- service() NOEXCEPT { }
- explicit service(int concurrency_hint) : _service(concurrency_hint) { }
+ service() NOEXCEPT {}
+ explicit service(int concurrency_hint) : _service(concurrency_hint) {}
- void reset()
- {
- _service.reset();
- }
-
- void run()
- {
- _service.run();
- }
-
- void stop()
- {
- _service.stop();
- }
-
- service_type& context() NOEXCEPT { return _service; }
-
-private:
-
- class event_item : public qtl::event
- {
- public:
- event_item(service& service, qtl::socket_type fd)
- : _service(service), _strand(service.context()), _socket(service.context(), NS_ASIO::ip::tcp::v4(), fd), _timer(service.context()), _busying(false)
- {
- }
-
- NS_ASIO::ip::tcp::socket& next_layer() { return _socket; }
-
- public: // qtl::event
- virtual void set_io_handler(int flags, long timeout, std::function<void(int)>&& handler) override
- {
- if (flags&qtl::event::ef_read)
+ void reset()
{
+ _service.reset();
+ }
+
+ void run()
+ {
+ _service.run();
+ }
+
+ void stop()
+ {
+ _service.stop();
+ }
+
+ service_type &context() NOEXCEPT { return _service; }
+
+ private:
+ class event_item : public qtl::event
+ {
+ public:
+ event_item(service &service, qtl::socket_type fd)
+ : _service(service), _strand(service.context()), _socket(service.context(), NS_ASIO::ip::tcp::v4(), fd), _timer(service.context()), _busying(false)
+ {
+ }
+
+ NS_ASIO::ip::tcp::socket &next_layer() { return _socket; }
+
+ public: // qtl::event
+ virtual void set_io_handler(int flags, long timeout, std::function<void(int)> &&handler) override
+ {
+ if (flags & qtl::event::ef_read)
+ {
#if ASIO_VERSION < 101200
- _socket.async_read_some(NS_ASIO::null_buffers(), _strand.wrap([this, handler](const NS_ASIO::error_code& ec, size_t bytes_transferred) {
+ _socket.async_read_some(NS_ASIO::null_buffers(), _strand.wrap([this, handler](const NS_ASIO::error_code &ec, size_t bytes_transferred)
+ {
#else
- _socket.async_wait(NS_ASIO::socket_base::wait_read, _strand.wrap([this, handler](const NS_ASIO::error_code& ec) {
+ _socket.async_wait(NS_ASIO::socket_base::wait_read, _strand.wrap([this, handler](const NS_ASIO::error_code &ec)
+ {
#endif // ASIO_VERSION
if (!ec)
handler(qtl::event::ef_read);
@@ -87,17 +88,18 @@
else
handler(qtl::event::ef_exception);
_busying = false;
- _timer.cancel();
- }));
- _busying = true;
- }
- if (flags&qtl::event::ef_write)
- {
+ _timer.cancel(); }));
+ _busying = true;
+ }
+ if (flags & qtl::event::ef_write)
+ {
#if ASIO_VERSION < 101200
- _socket.async_write_some(NS_ASIO::null_buffers(), _strand.wrap([this, handler](const NS_ASIO::error_code& ec, size_t bytes_transferred) {
+ _socket.async_write_some(NS_ASIO::null_buffers(), _strand.wrap([this, handler](const NS_ASIO::error_code &ec, size_t bytes_transferred)
+ {
#else
- _socket.async_wait(NS_ASIO::socket_base::wait_write, _strand.wrap([this, handler](const NS_ASIO::error_code& ec) {
-#endif //ASIO_VERSION
+ _socket.async_wait(NS_ASIO::socket_base::wait_write, _strand.wrap([this, handler](const NS_ASIO::error_code &ec)
+ {
+#endif // ASIO_VERSION
if (!ec)
handler(qtl::event::ef_write);
else if (ec == NS_ASIO::error::make_error_code(NS_ASIO::error::operation_aborted))
@@ -105,292 +107,315 @@
else
handler(qtl::event::ef_exception);
_timer.cancel();
- _busying = false;
- }));
- _busying = true;
- }
- if (timeout > 0)
- {
+ _busying = false; }));
+ _busying = true;
+ }
+ if (timeout > 0)
+ {
#if ASIO_VERSION < 101200
- _timer.expires_from_now(std::chrono::seconds(timeout));
+ _timer.expires_from_now(std::chrono::seconds(timeout));
#else
- _timer.expires_after(NS_ASIO::chrono::seconds(timeout));
+ _timer.expires_after(NS_ASIO::chrono::seconds(timeout));
#endif // ASIO_VERSION
- _timer.async_wait(_strand.wrap([this, handler](NS_ASIO::error_code ec) {
+ _timer.async_wait(_strand.wrap([this, handler](NS_ASIO::error_code ec)
+ {
if (!ec)
{
_socket.cancel(ec);
+ } }));
}
- }));
+ }
+
+ virtual void remove() override
+ {
+ if (_busying)
+ return;
+#if ASIO_VERSION >= 101200 && (!defined(_WIN32) || _WIN32_WINNT >= 0x0603)
+ _socket.release();
+#endif // Windows 8.1
+ _service.remove(this);
+ }
+ virtual bool is_busying() override
+ {
+ return _busying;
+ }
+
+ private:
+ service &_service;
+ service_type::strand _strand;
+ NS_ASIO::ip::tcp::socket _socket;
+ NS_ASIO::steady_timer _timer;
+ bool _busying;
+ };
+
+ public:
+ template <typename Connection>
+ event_item *add(Connection *connection)
+ {
+ event_item *item = new event_item(*this, connection->socket());
+ std::lock_guard<std::mutex> lock(_mutex);
+ _events.push_back(std::unique_ptr<event_item>(item));
+ return item;
}
- }
- virtual void remove() override
- {
- if (_busying) return;
-#if ASIO_VERSION >= 101200 && (!defined(_WIN32) || _WIN32_WINNT >= 0x0603 )
- _socket.release();
-#endif //Windows 8.1
- _service.remove(this);
- }
- virtual bool is_busying() override
- {
- return _busying;
- }
+ private:
+ service_type _service;
+ std::mutex _mutex;
+ std::vector<std::unique_ptr<event_item>> _events;
- private:
- service& _service;
- service_type::strand _strand;
- NS_ASIO::ip::tcp::socket _socket;
- NS_ASIO::steady_timer _timer;
- bool _busying;
- };
-
-public:
-
- template<typename Connection>
- event_item* add(Connection* connection)
- {
- event_item* item = new event_item(*this, connection->socket());
- std::lock_guard<std::mutex> lock(_mutex);
- _events.push_back(std::unique_ptr<event_item>(item));
- return item;
- }
-
-private:
- service_type _service;
- std::mutex _mutex;
- std::vector<std::unique_ptr<event_item>> _events;
-
- void remove(event_item* item)
- {
- std::lock_guard<std::mutex> lock(_mutex);
- auto it = std::find_if(_events.begin(), _events.end(), [item](std::unique_ptr<event_item>& v) {
- return item==v.get();
- });
- if (it != _events.end()) _events.erase(it);
- }
-};
+ void remove(event_item *item)
+ {
+ std::lock_guard<std::mutex> lock(_mutex);
+ auto it = std::find_if(_events.begin(), _events.end(), [item](std::unique_ptr<event_item> &v)
+ { return item == v.get(); });
+ if (it != _events.end())
+ _events.erase(it);
+ }
+ };
#if ASIO_VERSION < 101200
-template <typename Handler, typename Signature>
-using async_init_type = NS_ASIO::detail::async_result_init<Handler, Signature>;
+ template <typename Handler, typename Signature>
+ using async_init_type = NS_ASIO::detail::async_result_init<Handler, Signature>;
-template <typename Handler, typename Signature>
-inline typename NS_ASIO::handler_type<Handler, Signature>::type
-get_async_handler(async_init_type<Handler, Signature>& init)
-{
- return init.handler;
-}
+ template <typename Handler, typename Signature>
+ inline typename NS_ASIO::handler_type<Handler, Signature>::type
+ get_async_handler(async_init_type<Handler, Signature> &init)
+ {
+ return init.handler;
+ }
#else
-template <typename Handler, typename Signature>
-using async_init_type = NS_ASIO::async_completion<Handler, Signature>;
+ template <typename Handler, typename Signature>
+ using async_init_type = NS_ASIO::async_completion<Handler, Signature>;
-template <typename Handler, typename Signature>
-inline typename async_init_type<Handler, Signature>::completion_handler_type
-get_async_handler(async_init_type<Handler, Signature>& init)
-{
- return init.completion_handler;
-}
+ template <typename Handler, typename Signature>
+ inline typename async_init_type<Handler, Signature>::completion_handler_type
+ get_async_handler(async_init_type<Handler, Signature> &init)
+ {
+ return init.completion_handler;
+ }
#endif // ASIO_VERSION
-template<typename Connection, typename OpenHandler, typename... Args>
-inline ASIO_INITFN_RESULT_TYPE(OpenHandler, void(typename Connection::exception_type))
-async_open(service& service, Connection& db, OpenHandler&& handler, Args&&... args)
-{
+ template <typename Connection, typename OpenHandler, typename... Args>
+ inline ASIO_INITFN_RESULT_TYPE(OpenHandler, void(typename Connection::exception_type))
+ async_open(service &service, Connection &db, OpenHandler &&handler, Args &&...args)
+ {
#if ASIO_VERSION < 101200
- async_init_type<OpenHandler,
- void(typename Connection::exception_type)> init(std::forward<OpenHandler>(handler));
+ async_init_type<OpenHandler,
+ void(typename Connection::exception_type)>
+ init(std::forward<OpenHandler>(handler));
#else
- async_init_type<OpenHandler,
- void(typename Connection::exception_type)> init(handler);
+ async_init_type<OpenHandler,
+ void(typename Connection::exception_type)>
+ init(handler);
#endif
- db.open(service, get_async_handler(init), std::forward<Args>(args)...);
- return init.result.get();
-}
+ db.open(service, get_async_handler(init), std::forward<Args>(args)...);
+ return init.result.get();
+ }
-template<typename Connection, typename CloseHandler, typename... Args>
-inline ASIO_INITFN_RESULT_TYPE(CloseHandler, void())
-async_close(Connection& db, CloseHandler&& handler, Args&&... args)
-{
+ template <typename Connection, typename CloseHandler, typename... Args>
+ inline ASIO_INITFN_RESULT_TYPE(CloseHandler, void())
+ async_close(Connection &db, CloseHandler &&handler, Args &&...args)
+ {
#if ASIO_VERSION < 101200
- async_init_type<CloseHandler,
- void()> init(std::forward<CloseHandler>(std::forward<CloseHandler>(handler)));
+ async_init_type<CloseHandler,
+ void()>
+ init(std::forward<CloseHandler>(std::forward<CloseHandler>(handler)));
#else
- async_init_type<CloseHandler,
- void()> init(std::forward<CloseHandler>(handler));
+ async_init_type<CloseHandler,
+ void()>
+ init(std::forward<CloseHandler>(handler));
#endif
- db.close(get_async_handler(init), std::forward<Args>(args)...);
- return init.result.get();
-}
+ db.close(get_async_handler(init), std::forward<Args>(args)...);
+ return init.result.get();
+ }
-template<typename Connection, typename ExecuteHandler, typename... Args>
-inline ASIO_INITFN_RESULT_TYPE(ExecuteHandler, void(typename Connection::exception_type, uint64_t))
-async_execute(Connection& db, ExecuteHandler&& handler, Args&&... args)
-{
+ template <typename Connection, typename ExecuteHandler, typename... Args>
+ inline ASIO_INITFN_RESULT_TYPE(ExecuteHandler, void(typename Connection::exception_type, uint64_t))
+ async_execute(Connection &db, ExecuteHandler &&handler, Args &&...args)
+ {
#if ASIO_VERSION < 101200
- async_init_type<ExecuteHandler,
- void(typename Connection::exception_type, uint64_t)> init(std::forward<ExecuteHandler>(handler));
+ async_init_type<ExecuteHandler,
+ void(typename Connection::exception_type, uint64_t)>
+ init(std::forward<ExecuteHandler>(handler));
#else
- async_init_type<ExecuteHandler,
- void(typename Connection::exception_type, uint64_t)> init(handler);
+ async_init_type<ExecuteHandler,
+ void(typename Connection::exception_type, uint64_t)>
+ init(handler);
#endif
- db.execute(get_async_handler(init), std::forward<Args>(args)...);
- return init.result.get();
-}
+ db.execute(get_async_handler(init), std::forward<Args>(args)...);
+ return init.result.get();
+ }
-template<typename Connection, typename ExecuteHandler, typename... Args>
-inline ASIO_INITFN_RESULT_TYPE(ExecuteHandler, void(typename Connection::exception_type, uint64_t))
-async_execute_direct(Connection& db, ExecuteHandler&& handler, Args&&... args)
-{
+ template <typename Connection, typename ExecuteHandler, typename... Args>
+ inline ASIO_INITFN_RESULT_TYPE(ExecuteHandler, void(typename Connection::exception_type, uint64_t))
+ async_execute_direct(Connection &db, ExecuteHandler &&handler, Args &&...args)
+ {
#if ASIO_VERSION < 101200
- async_init_type<ExecuteHandler,
- void(typename Connection::exception_type, uint64_t)> init(std::forward<ExecuteHandler>(handler));
+ async_init_type<ExecuteHandler,
+ void(typename Connection::exception_type, uint64_t)>
+ init(std::forward<ExecuteHandler>(handler));
#else
- async_init_type<ExecuteHandler,
- void(typename Connection::exception_type, uint64_t)> init(handler);
+ async_init_type<ExecuteHandler,
+ void(typename Connection::exception_type, uint64_t)>
+ init(handler);
#endif
- db.execute_direct(get_async_handler(init), std::forward<Args>(args)...);
- return init.result.get();
-}
+ db.execute_direct(get_async_handler(init), std::forward<Args>(args)...);
+ return init.result.get();
+ }
-template<typename Connection, typename ExecuteHandler, typename... Args>
-inline ASIO_INITFN_RESULT_TYPE(ExecuteHandler, void(typename Connection::exception_type, uint64_t))
- async_insert(Connection& db, ExecuteHandler&& handler, Args&&... args)
-{
+ template <typename Connection, typename ExecuteHandler, typename... Args>
+ inline ASIO_INITFN_RESULT_TYPE(ExecuteHandler, void(typename Connection::exception_type, uint64_t))
+ async_insert(Connection &db, ExecuteHandler &&handler, Args &&...args)
+ {
#if ASIO_VERSION < 101200
- async_init_type<ExecuteHandler,
- void(typename Connection::exception_type, uint64_t)> init(std::forward<ExecuteHandler>(handler));
+ async_init_type<ExecuteHandler,
+ void(typename Connection::exception_type, uint64_t)>
+ init(std::forward<ExecuteHandler>(handler));
#else
- async_init_type<ExecuteHandler,
- void(typename Connection::exception_type, uint64_t)> init(handler);
+ async_init_type<ExecuteHandler,
+ void(typename Connection::exception_type, uint64_t)>
+ init(handler);
#endif
- db.insert(get_async_handler(init), std::forward<Args>(args)...);
- return init.result.get();
-}
+ db.insert(get_async_handler(init), std::forward<Args>(args)...);
+ return init.result.get();
+ }
-template<typename Connection, typename ExecuteHandler, typename... Args>
-inline ASIO_INITFN_RESULT_TYPE(ExecuteHandler, void(typename Connection::exception_type, uint64_t))
- async_insert_direct(Connection& db, ExecuteHandler&& handler, Args&&... args)
-{
+ template <typename Connection, typename ExecuteHandler, typename... Args>
+ inline ASIO_INITFN_RESULT_TYPE(ExecuteHandler, void(typename Connection::exception_type, uint64_t))
+ async_insert_direct(Connection &db, ExecuteHandler &&handler, Args &&...args)
+ {
#if ASIO_VERSION < 101200
- async_init_type<ExecuteHandler,
- void(typename Connection::exception_type, uint64_t)> init(std::forward<ExecuteHandler>(handler));
+ async_init_type<ExecuteHandler,
+ void(typename Connection::exception_type, uint64_t)>
+ init(std::forward<ExecuteHandler>(handler));
#else
- async_init_type<ExecuteHandler,
- void(typename Connection::exception_type, uint64_t)> init(handler);
+ async_init_type<ExecuteHandler,
+ void(typename Connection::exception_type, uint64_t)>
+ init(handler);
#endif
- db.insert_direct(get_async_handler(init), std::forward<Args>(args)...);
- return init.result.get();
-}
+ db.insert_direct(get_async_handler(init), std::forward<Args>(args)...);
+ return init.result.get();
+ }
-template<typename Connection, typename FinishHandler, typename... Args>
-inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
- async_query(Connection& db, FinishHandler&& handler, Args&&... args)
-{
+ template <typename Connection, typename FinishHandler, typename... Args>
+ inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
+ async_query(Connection &db, FinishHandler &&handler, Args &&...args)
+ {
#if ASIO_VERSION < 101200
- async_init_type<FinishHandler,
- void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler));
+ async_init_type<FinishHandler,
+ void(typename Connection::exception_type)>
+ init(std::forward<FinishHandler>(handler));
#else
- async_init_type<FinishHandler,
- void(typename Connection::exception_type)> init(handler);
+ async_init_type<FinishHandler,
+ void(typename Connection::exception_type)>
+ init(handler);
#endif
- db.query(std::forward<Args>(args)..., get_async_handler(init));
- return init.result.get();
-}
+ db.query(std::forward<Args>(args)..., get_async_handler(init));
+ return init.result.get();
+ }
-template<typename Connection, typename FinishHandler, typename... Args>
-inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
-async_query_explicit(Connection& db, FinishHandler&& handler, Args&&... args)
-{
+ template <typename Connection, typename FinishHandler, typename... Args>
+ inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
+ async_query_explicit(Connection &db, FinishHandler &&handler, Args &&...args)
+ {
#if ASIO_VERSION < 101200
- async_init_type<FinishHandler,
- void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler));
+ async_init_type<FinishHandler,
+ void(typename Connection::exception_type)>
+ init(std::forward<FinishHandler>(handler));
#else
- async_init_type<FinishHandler,
- void(typename Connection::exception_type)> init(handler);
+ async_init_type<FinishHandler,
+ void(typename Connection::exception_type)>
+ init(handler);
#endif
- db.query_explicit(std::forward<Args>(args)..., get_async_handler(init));
- return init.result.get();
-}
+ db.query_explicit(std::forward<Args>(args)..., get_async_handler(init));
+ return init.result.get();
+ }
-template<typename Connection, typename A1, typename A2, typename FinishHandler, typename... RowHandlers>
-inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
-async_query_multi_with_params(Connection& db, A1&& a1, A2&& a2, FinishHandler&& handler, RowHandlers&&... row_handlers)
-{
+ template <typename Connection, typename A1, typename A2, typename FinishHandler, typename... RowHandlers>
+ inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
+ async_query_multi_with_params(Connection &db, A1 &&a1, A2 &&a2, FinishHandler &&handler, RowHandlers &&...row_handlers)
+ {
#if ASIO_VERSION < 101200
- async_init_type<FinishHandler,
- void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler));
+ async_init_type<FinishHandler,
+ void(typename Connection::exception_type)>
+ init(std::forward<FinishHandler>(handler));
#else
- async_init_type<FinishHandler,
- void(typename Connection::exception_type)> init(handler);
+ async_init_type<FinishHandler,
+ void(typename Connection::exception_type)>
+ init(handler);
#endif
- db.query_multi_with_params(std::forward<A1>(a1), std::forward<A2>(a2), get_async_handler(init), std::forward<RowHandlers>(row_handlers)...);
- return init.result.get();
-}
+ db.query_multi_with_params(std::forward<A1>(a1), std::forward<A2>(a2), get_async_handler(init), std::forward<RowHandlers>(row_handlers)...);
+ return init.result.get();
+ }
-template<typename Connection, typename A1, typename FinishHandler, typename... RowHandlers>
-inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
-async_query_multi_with_params(Connection& db, A1&& a1, FinishHandler&& handler, RowHandlers&&... row_handlers)
-{
+ template <typename Connection, typename A1, typename FinishHandler, typename... RowHandlers>
+ inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
+ async_query_multi_with_params(Connection &db, A1 &&a1, FinishHandler &&handler, RowHandlers &&...row_handlers)
+ {
#if ASIO_VERSION < 101200
- async_init_type<FinishHandler,
- void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler));
+ async_init_type<FinishHandler,
+ void(typename Connection::exception_type)>
+ init(std::forward<FinishHandler>(handler));
#else
- async_init_type<FinishHandler,
- void(typename Connection::exception_type)> init(handler);
+ async_init_type<FinishHandler,
+ void(typename Connection::exception_type)>
+ init(handler);
#endif
- db.query_multi_with_params(std::forward<A1>(a1), get_async_handler(init), std::forward<RowHandlers>(row_handlers)...);
- return init.result.get();
-}
+ db.query_multi_with_params(std::forward<A1>(a1), get_async_handler(init), std::forward<RowHandlers>(row_handlers)...);
+ return init.result.get();
+ }
-template<typename Connection, typename A1, typename A2, typename FinishHandler, typename... RowHandlers>
-inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
-async_query_multi(Connection& db, A1&& a1, A2&& a2, FinishHandler&& handler, RowHandlers&&... row_handlers)
-{
+ template <typename Connection, typename A1, typename A2, typename FinishHandler, typename... RowHandlers>
+ inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
+ async_query_multi(Connection &db, A1 &&a1, A2 &&a2, FinishHandler &&handler, RowHandlers &&...row_handlers)
+ {
#if ASIO_VERSION < 101200
- async_init_type<FinishHandler,
- void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler));
+ async_init_type<FinishHandler,
+ void(typename Connection::exception_type)>
+ init(std::forward<FinishHandler>(handler));
#else
- async_init_type<FinishHandler,
- void(typename Connection::exception_type)> init(handler);
+ async_init_type<FinishHandler,
+ void(typename Connection::exception_type)>
+ init(handler);
#endif
- db.query_multi(std::forward<A1>(a1), std::forward<A2>(a2), get_async_handler(init), std::forward<RowHandlers>(row_handlers)...);
- return init.result.get();
-}
+ db.query_multi(std::forward<A1>(a1), std::forward<A2>(a2), get_async_handler(init), std::forward<RowHandlers>(row_handlers)...);
+ return init.result.get();
+ }
-template<typename Connection, typename A1, typename FinishHandler, typename... RowHandlers>
-inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
-async_query_multi(Connection& db, A1&& a1, FinishHandler&& handler, RowHandlers&&... row_handlers)
-{
+ template <typename Connection, typename A1, typename FinishHandler, typename... RowHandlers>
+ inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
+ async_query_multi(Connection &db, A1 &&a1, FinishHandler &&handler, RowHandlers &&...row_handlers)
+ {
#if ASIO_VERSION < 101200
- async_init_type<FinishHandler,
- void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler));
+ async_init_type<FinishHandler,
+ void(typename Connection::exception_type)>
+ init(std::forward<FinishHandler>(handler));
#else
- async_init_type<FinishHandler,
- void(typename Connection::exception_type)> init(handler);
+ async_init_type<FinishHandler,
+ void(typename Connection::exception_type)>
+ init(handler);
#endif
- db.query_multi(std::forward<A1>(a1), get_async_handler(init), std::forward<RowHandlers>(row_handlers)...);
- return init.result.get();
-}
+ db.query_multi(std::forward<A1>(a1), get_async_handler(init), std::forward<RowHandlers>(row_handlers)...);
+ return init.result.get();
+ }
-}
+ }
}
diff --git a/include/qtl_async.hpp b/include/qtl_async.hpp
index eeb98d5..41893b5 100644
--- a/include/qtl_async.hpp
+++ b/include/qtl_async.hpp
@@ -13,26 +13,26 @@
typedef SOCKET socket_type;
#else
typedef int socket_type;
-#endif
+#endif
-namespace detail
-{
-
-template<typename Values, typename RowHandler, typename FinishHandler>
-struct async_fetch_helper : public std::enable_shared_from_this<async_fetch_helper<Values, RowHandler, FinishHandler>>
-{
- async_fetch_helper(const Values& values, const RowHandler& row_handler, const FinishHandler& finish_handler)
- : m_values(values), m_row_handler(row_handler), m_finish_handler(finish_handler), m_auto_close_command(true)
+ namespace detail
{
- }
- template<typename Command, typename Exception>
- void start(const std::shared_ptr<Command>& command)
- {
- auto self = this->shared_from_this();
- command->fetch(std::forward<Values>(m_values), [this, command]() {
- return qtl::detail::apply<RowHandler, Values>(std::forward<RowHandler>(m_row_handler), std::forward<Values>(m_values));
- }, [self, command](const Exception& e) {
+ template <typename Values, typename RowHandler, typename FinishHandler>
+ struct async_fetch_helper : public std::enable_shared_from_this<async_fetch_helper<Values, RowHandler, FinishHandler>>
+ {
+ async_fetch_helper(const Values &values, const RowHandler &row_handler, const FinishHandler &finish_handler)
+ : m_values(values), m_row_handler(row_handler), m_finish_handler(finish_handler), m_auto_close_command(true)
+ {
+ }
+
+ template <typename Command, typename Exception>
+ void start(const std::shared_ptr<Command> &command)
+ {
+ auto self = this->shared_from_this();
+ command->fetch(std::forward<Values>(m_values), [this, command]()
+ { return qtl::detail::apply<RowHandler, Values>(std::forward<RowHandler>(m_row_handler), std::forward<Values>(m_values)); }, [self, command](const Exception &e)
+ {
if (e || self->m_auto_close_command)
{
command->close([self, command, e](const Exception& new_e) {
@@ -42,43 +42,42 @@
else
{
self->m_finish_handler(e);
+ } });
}
- });
- }
-
- void auto_close_command(bool auto_close)
- {
- m_auto_close_command = auto_close;
- }
-private:
- Values m_values;
- RowHandler m_row_handler;
- FinishHandler m_finish_handler;
- bool m_auto_close_command;
-};
+ void auto_close_command(bool auto_close)
+ {
+ m_auto_close_command = auto_close;
+ }
-template<typename Values, typename RowHandler, typename FinishHandler>
-inline std::shared_ptr<async_fetch_helper<Values, RowHandler, FinishHandler>> make_fetch_helper(const Values& values, const RowHandler& row_handler, const FinishHandler& cpmplete_handler)
-{
- return std::make_shared<async_fetch_helper<Values, RowHandler, FinishHandler>>(values, row_handler, cpmplete_handler);
-}
+ private:
+ Values m_values;
+ RowHandler m_row_handler;
+ FinishHandler m_finish_handler;
+ bool m_auto_close_command;
+ };
+ template <typename Values, typename RowHandler, typename FinishHandler>
+ inline std::shared_ptr<async_fetch_helper<Values, RowHandler, FinishHandler>> make_fetch_helper(const Values &values, const RowHandler &row_handler, const FinishHandler &cpmplete_handler)
+ {
+ return std::make_shared<async_fetch_helper<Values, RowHandler, FinishHandler>>(values, row_handler, cpmplete_handler);
+ }
-template<typename Exception, typename Command, typename RowHandler, typename FinishHandler>
-inline void async_fetch_command(const std::shared_ptr<Command>& command, FinishHandler&& finish_handler, RowHandler&& row_handler)
-{
- auto values=make_values(row_handler);
- typedef decltype(values) values_type;
- auto helper = make_fetch_helper(std::forward<values_type>(values), std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
- helper->auto_close_command(false);
- helper->template start<Command, Exception>(command);
-}
+ template <typename Exception, typename Command, typename RowHandler, typename FinishHandler>
+ inline void async_fetch_command(const std::shared_ptr<Command> &command, FinishHandler &&finish_handler, RowHandler &&row_handler)
+ {
+ auto values = make_values(row_handler);
+ typedef decltype(values) values_type;
+ auto helper = make_fetch_helper(std::forward<values_type>(values), std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
+ helper->auto_close_command(false);
+ helper->template start<Command, Exception>(command);
+ }
-template<typename Exception, typename Command, typename RowHandler, typename FinishHandler, typename... OtherHandler>
-inline void async_fetch_command(const std::shared_ptr<Command>& command, FinishHandler&& finish_handler, RowHandler&& row_handler, OtherHandler&&... other)
-{
- async_fetch_command<Exception>(command, [command, finish_handler, other...](const Exception& e) mutable {
+ template <typename Exception, typename Command, typename RowHandler, typename FinishHandler, typename... OtherHandler>
+ inline void async_fetch_command(const std::shared_ptr<Command> &command, FinishHandler &&finish_handler, RowHandler &&row_handler, OtherHandler &&...other)
+ {
+ async_fetch_command<Exception>(command, [command, finish_handler, other...](const Exception &e) mutable
+ {
if (e)
{
finish_handler(e);
@@ -91,76 +90,76 @@
else
async_fetch_command<Exception>(command, std::forward<FinishHandler>(finish_handler), std::forward<OtherHandler>(other)...);
});
+ } }, std::forward<RowHandler>(row_handler));
}
- }, std::forward<RowHandler>(row_handler));
-}
-}
+ }
-struct event
-{
- enum io_flags
+ struct event
{
- ef_read = 0x1,
- ef_write = 0x2,
- ef_exception = 0x4,
- ef_timeout =0x8,
- ev_all = ef_read | ef_write | ef_exception
+ enum io_flags
+ {
+ ef_read = 0x1,
+ ef_write = 0x2,
+ ef_exception = 0x4,
+ ef_timeout = 0x8,
+ ev_all = ef_read | ef_write | ef_exception
+ };
+
+ virtual ~event() {}
+ virtual void set_io_handler(int flags, long timeout, std::function<void(int)> &&) = 0;
+ virtual void remove() = 0;
+ virtual bool is_busying() = 0;
};
- virtual ~event() { }
- virtual void set_io_handler(int flags, long timeout, std::function<void(int)>&&) = 0;
- virtual void remove() = 0;
- virtual bool is_busying() = 0;
-};
-
-template<typename T, class Command>
-class async_connection
-{
-public:
- template<typename EventLoop>
- bool bind(EventLoop& ev)
+ template <typename T, class Command>
+ class async_connection
{
- T* pThis = static_cast<T*>(this);
- if(m_event_handler)
+ public:
+ template <typename EventLoop>
+ bool bind(EventLoop &ev)
{
- if(m_event_handler->is_busying())
- return false;
- unbind();
+ T *pThis = static_cast<T *>(this);
+ if (m_event_handler)
+ {
+ if (m_event_handler->is_busying())
+ return false;
+ unbind();
+ }
+ m_event_handler = ev.add(pThis);
+ return m_event_handler != nullptr;
}
- m_event_handler = ev.add(pThis);
- return m_event_handler!=nullptr;
- }
- qtl::event* event() const
- {
- return m_event_handler;
- }
-
- bool unbind()
- {
- if(m_event_handler)
+ qtl::event *event() const
{
- if(m_event_handler->is_busying())
- return false;
- m_event_handler->remove();
- m_event_handler=nullptr;
+ return m_event_handler;
}
- return true;
- }
- /*
- ResultHandler defines as:
- void handler(const exception_type& e, uint64_t affected=0);
- Copies will be made of the handler as required.
- If an error occurred, value of affected is undefined.
- Note: parameter affected must has default value.
- */
- template<typename Params, typename ResultHandler>
- void execute(ResultHandler handler, const char* query_text, size_t text_length, const Params& params)
- {
- T* pThis = static_cast<T*>(this);
- pThis->open_command(query_text, text_length, [handler, params](const typename T::exception_type& e, std::shared_ptr<Command>& command) mutable {
+ bool unbind()
+ {
+ if (m_event_handler)
+ {
+ if (m_event_handler->is_busying())
+ return false;
+ m_event_handler->remove();
+ m_event_handler = nullptr;
+ }
+ return true;
+ }
+
+ /*
+ ResultHandler defines as:
+ void handler(const exception_type& e, uint64_t affected=0);
+ Copies will be made of the handler as required.
+ If an error occurred, value of affected is undefined.
+ Note: parameter affected must has default value.
+ */
+ template <typename Params, typename ResultHandler>
+ void execute(ResultHandler handler, const char *query_text, size_t text_length, const Params ¶ms)
+ {
+ T *pThis = static_cast<T *>(this);
+ pThis->open_command(query_text, text_length, [handler, params](const typename T::exception_type &e, std::shared_ptr<Command> &command) mutable
+ {
if(e)
{
command->close([command, e, handler](const typename T::exception_type& ae) mutable {
@@ -172,49 +171,49 @@
command->close([command, handler, e, affected](const typename T::exception_type& ae) mutable {
handler(e ? e : ae, affected);
});
- });
- });
- }
- template<typename Params, typename ResultHandler>
- void execute(ResultHandler handler, const char* query_text, const Params& params)
- {
- return execute(std::forward<ResultHandler>(handler), query_text, strlen(query_text), params);
- }
- template<typename Params, typename ResultHandler>
- void execute(ResultHandler handler, const std::string& query_text, const Params& params)
- {
- return execute(std::forward<ResultHandler>(handler), query_text.data(), query_text.length(), params);
- }
+ }); });
+ }
+ template <typename Params, typename ResultHandler>
+ void execute(ResultHandler handler, const char *query_text, const Params ¶ms)
+ {
+ return execute(std::forward<ResultHandler>(handler), query_text, strlen(query_text), params);
+ }
+ template <typename Params, typename ResultHandler>
+ void execute(ResultHandler handler, const std::string &query_text, const Params ¶ms)
+ {
+ return execute(std::forward<ResultHandler>(handler), query_text.data(), query_text.length(), params);
+ }
- template<typename... Params, typename ResultHandler>
- void execute_direct(ResultHandler handler, const char* query_text, size_t text_length, const Params&... params)
- {
- execute(std::forward<ResultHandler>(handler), query_text, text_length, std::forward_as_tuple(params...));
- }
- template<typename... Params, typename ResultHandler>
- void execute_direct(ResultHandler handler, const char* query_text, const Params&... params)
- {
- execute(std::forward<ResultHandler>(handler), query_text, std::forward_as_tuple(params...));
- }
- template<typename... Params, typename ResultHandler>
- void execute_direct(ResultHandler handler, const std::string& query_text, const Params&... params)
- {
- execute(std::forward<ResultHandler>(handler), query_text, query_text, std::forward_as_tuple(params...));
- }
+ template <typename... Params, typename ResultHandler>
+ void execute_direct(ResultHandler handler, const char *query_text, size_t text_length, const Params &...params)
+ {
+ execute(std::forward<ResultHandler>(handler), query_text, text_length, std::forward_as_tuple(params...));
+ }
+ template <typename... Params, typename ResultHandler>
+ void execute_direct(ResultHandler handler, const char *query_text, const Params &...params)
+ {
+ execute(std::forward<ResultHandler>(handler), query_text, std::forward_as_tuple(params...));
+ }
+ template <typename... Params, typename ResultHandler>
+ void execute_direct(ResultHandler handler, const std::string &query_text, const Params &...params)
+ {
+ execute(std::forward<ResultHandler>(handler), query_text, query_text, std::forward_as_tuple(params...));
+ }
- /*
- ResultHandler defines as:
- void handler(const exception_type& e, uint64_t insert_id=0);
- Copies will be made of the handler as required.
- If an error occurred, value of insert_id is undefined.
- If the command is not insert statement, value of insert_id is zero.
- Note: parameter insert_id must has default value.
- */
- template<typename Params, typename ResultHandler>
- void insert(ResultHandler handler, const char* query_text, size_t text_length, const Params& params)
- {
- T* pThis = static_cast<T*>(this);
- pThis->open_command(query_text, text_length, [handler, params](const typename T::exception_type& e, std::shared_ptr<Command>& command) {
+ /*
+ ResultHandler defines as:
+ void handler(const exception_type& e, uint64_t insert_id=0);
+ Copies will be made of the handler as required.
+ If an error occurred, value of insert_id is undefined.
+ If the command is not insert statement, value of insert_id is zero.
+ Note: parameter insert_id must has default value.
+ */
+ template <typename Params, typename ResultHandler>
+ void insert(ResultHandler handler, const char *query_text, size_t text_length, const Params ¶ms)
+ {
+ T *pThis = static_cast<T *>(this);
+ pThis->open_command(query_text, text_length, [handler, params](const typename T::exception_type &e, std::shared_ptr<Command> &command)
+ {
if(e)
{
command->close([command, e, handler](const typename T::exception_type& ae) mutable {
@@ -231,53 +230,53 @@
handler(e ? e : ae, insert_id);
});
});
- }
- });
- }
+ } });
+ }
- template<typename Params, typename ResultHandler>
- void insert(ResultHandler&& handler, const char* query_text, const Params& params)
- {
- insert(std::forward<ResultHandler>(handler), query_text, strlen(query_text), params);
- }
+ template <typename Params, typename ResultHandler>
+ void insert(ResultHandler &&handler, const char *query_text, const Params ¶ms)
+ {
+ insert(std::forward<ResultHandler>(handler), query_text, strlen(query_text), params);
+ }
- template<typename Params, typename ResultHandler>
- void insert(ResultHandler&& handler, const std::string& query_text, const Params& params)
- {
- insert(std::forward<ResultHandler>(handler), query_text.data(), query_text.length(), params);
- }
+ template <typename Params, typename ResultHandler>
+ void insert(ResultHandler &&handler, const std::string &query_text, const Params ¶ms)
+ {
+ insert(std::forward<ResultHandler>(handler), query_text.data(), query_text.length(), params);
+ }
- template<typename... Params, typename ResultHandler>
- void insert_direct(ResultHandler&& handler, const char* query_text, size_t text_length, const Params&... params)
- {
- insert(std::forward<ResultHandler>(handler), query_text, text_length, std::forward_as_tuple(params...));
- }
+ template <typename... Params, typename ResultHandler>
+ void insert_direct(ResultHandler &&handler, const char *query_text, size_t text_length, const Params &...params)
+ {
+ insert(std::forward<ResultHandler>(handler), query_text, text_length, std::forward_as_tuple(params...));
+ }
- template<typename... Params, typename ResultHandler>
- void insert_direct(ResultHandler&& handler, const char* query_text, const Params&... params)
- {
- insert(std::forward<ResultHandler>(handler), query_text, strlen(query_text), std::forward_as_tuple(params...));
- }
+ template <typename... Params, typename ResultHandler>
+ void insert_direct(ResultHandler &&handler, const char *query_text, const Params &...params)
+ {
+ insert(std::forward<ResultHandler>(handler), query_text, strlen(query_text), std::forward_as_tuple(params...));
+ }
- template<typename... Params, typename ResultHandler>
- void insert_direct(ResultHandler&& handler, const std::string& query_text, const Params&... params)
- {
- insert(std::forward<ResultHandler>(handler), query_text.data(), query_text.length(), std::forward_as_tuple(params...));
- }
+ template <typename... Params, typename ResultHandler>
+ void insert_direct(ResultHandler &&handler, const std::string &query_text, const Params &...params)
+ {
+ insert(std::forward<ResultHandler>(handler), query_text.data(), query_text.length(), std::forward_as_tuple(params...));
+ }
- /*
- RowHandler defines as:
- void row_handler(const Values& values);
- FinishHandler defines as:
- void finish_handler(const exception_type& e);
- If a row is fetched, the row handler is called.
- If an error occurred or the operation is completed, the result handler is called.
- */
- template<typename Params, typename Values, typename RowHandler, typename FinishHandler>
- void query_explicit(const char* query_text, size_t text_length, const Params& params, Values&& values, RowHandler&& row_handler, FinishHandler&& finish_handler)
- {
- T* pThis = static_cast<T*>(this);
- pThis->open_command(query_text, text_length, [values, row_handler, finish_handler, params](const typename T::exception_type& e, const std::shared_ptr<Command>& command) mutable {
+ /*
+ RowHandler defines as:
+ void row_handler(const Values& values);
+ FinishHandler defines as:
+ void finish_handler(const exception_type& e);
+ If a row is fetched, the row handler is called.
+ If an error occurred or the operation is completed, the result handler is called.
+ */
+ template <typename Params, typename Values, typename RowHandler, typename FinishHandler>
+ void query_explicit(const char *query_text, size_t text_length, const Params ¶ms, Values &&values, RowHandler &&row_handler, FinishHandler &&finish_handler)
+ {
+ T *pThis = static_cast<T *>(this);
+ pThis->open_command(query_text, text_length, [values, row_handler, finish_handler, params](const typename T::exception_type &e, const std::shared_ptr<Command> &command) mutable
+ {
if(e)
{
finish_handler(e);
@@ -288,72 +287,72 @@
auto helper=detail::make_fetch_helper(values, row_handler, finish_handler);
helper->template start<Command, typename T::exception_type>(command);
});
- }
- });
- }
+ } });
+ }
- template<typename Params, typename Values, typename RowHandler, typename FinishHandler>
- void query_explicit(const char* query_text, const Params& params, Values&& values, RowHandler&& row_handler, FinishHandler&& finish_handler)
- {
- query_explicit(query_text, strlen(query_text), params, std::forward<Values>(values), std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
- }
- template<typename Params, typename Values, typename RowHandler, typename FinishHandler>
- void query_explicit(const std::string& query_text, const Params& params, Values&& values, RowHandler&& row_handler, FinishHandler&& finish_handler)
- {
- query_explicit(query_text.data(), query_text.size(), params, std::forward<Values>(values), std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
- }
- template<typename Values, typename RowHandler, typename FinishHandler>
- void query_explicit(const char* query_text, size_t text_length, Values&& values, RowHandler&& row_handler, FinishHandler&& finish_handler)
- {
- query_explicit(query_text, text_length, std::make_tuple(), std::forward<Values>(values), std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
- }
- template<typename Values, typename RowHandler, typename FinishHandler>
- void query_explicit(const char* query_text, Values&& values, RowHandler&& row_handler, FinishHandler&& finish_handler)
- {
- query_explicit(query_text, strlen(query_text), std::make_tuple(), std::forward<Values>(values), std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
- }
- template<typename Values, typename RowHandler, typename FinishHandler>
- void query_explicit(const std::string& query_text, Values&& values, RowHandler&& row_handler, FinishHandler&& finish_handler)
- {
- query_explicit(query_text, std::make_tuple(), std::forward<Values>(values), std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
- }
+ template <typename Params, typename Values, typename RowHandler, typename FinishHandler>
+ void query_explicit(const char *query_text, const Params ¶ms, Values &&values, RowHandler &&row_handler, FinishHandler &&finish_handler)
+ {
+ query_explicit(query_text, strlen(query_text), params, std::forward<Values>(values), std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
+ }
+ template <typename Params, typename Values, typename RowHandler, typename FinishHandler>
+ void query_explicit(const std::string &query_text, const Params ¶ms, Values &&values, RowHandler &&row_handler, FinishHandler &&finish_handler)
+ {
+ query_explicit(query_text.data(), query_text.size(), params, std::forward<Values>(values), std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
+ }
+ template <typename Values, typename RowHandler, typename FinishHandler>
+ void query_explicit(const char *query_text, size_t text_length, Values &&values, RowHandler &&row_handler, FinishHandler &&finish_handler)
+ {
+ query_explicit(query_text, text_length, std::make_tuple(), std::forward<Values>(values), std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
+ }
+ template <typename Values, typename RowHandler, typename FinishHandler>
+ void query_explicit(const char *query_text, Values &&values, RowHandler &&row_handler, FinishHandler &&finish_handler)
+ {
+ query_explicit(query_text, strlen(query_text), std::make_tuple(), std::forward<Values>(values), std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
+ }
+ template <typename Values, typename RowHandler, typename FinishHandler>
+ void query_explicit(const std::string &query_text, Values &&values, RowHandler &&row_handler, FinishHandler &&finish_handler)
+ {
+ query_explicit(query_text, std::make_tuple(), std::forward<Values>(values), std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
+ }
- template<typename Params, typename RowHandler, typename FinishHandler>
- void query(const char* query_text, size_t text_length, const Params& params, RowHandler&& row_handler, FinishHandler&& finish_handler)
- {
- query_explicit(query_text, text_length, params, detail::make_values(row_handler), std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
- }
- template<typename Params, typename RowHandler, typename FinishHandler>
- void query(const char* query_text, const Params& params, RowHandler&& row_handler, FinishHandler&& finish_handler)
- {
- query_explicit(query_text, params, detail::make_values(row_handler), std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
- }
- template<typename Params, typename RowHandler, typename FinishHandler>
- void query(const std::string& query_text, const Params& params, RowHandler&& row_handler, FinishHandler&& finish_handler)
- {
- query_explicit(query_text, params, detail::make_values(row_handler), std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
- }
- template<typename RowHandler, typename FinishHandler>
- void query(const char* query_text, size_t text_length, RowHandler&& row_handler, FinishHandler&& finish_handler)
- {
- query_explicit(query_text, text_length, detail::make_values(row_handler), std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
- }
- template<typename RowHandler, typename FinishHandler>
- void query(const char* query_text, RowHandler&& row_handler, FinishHandler&& finish_handler)
- {
- query_explicit(query_text, detail::make_values(row_handler), std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
- }
- template<typename RowHandler, typename FinishHandler>
- void query(const std::string& query_text, RowHandler&& row_handler, FinishHandler&& finish_handler)
- {
- query_explicit(query_text, detail::make_values(row_handler), std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
- }
+ template <typename Params, typename RowHandler, typename FinishHandler>
+ void query(const char *query_text, size_t text_length, const Params ¶ms, RowHandler &&row_handler, FinishHandler &&finish_handler)
+ {
+ query_explicit(query_text, text_length, params, detail::make_values(row_handler), std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
+ }
+ template <typename Params, typename RowHandler, typename FinishHandler>
+ void query(const char *query_text, const Params ¶ms, RowHandler &&row_handler, FinishHandler &&finish_handler)
+ {
+ query_explicit(query_text, params, detail::make_values(row_handler), std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
+ }
+ template <typename Params, typename RowHandler, typename FinishHandler>
+ void query(const std::string &query_text, const Params ¶ms, RowHandler &&row_handler, FinishHandler &&finish_handler)
+ {
+ query_explicit(query_text, params, detail::make_values(row_handler), std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
+ }
+ template <typename RowHandler, typename FinishHandler>
+ void query(const char *query_text, size_t text_length, RowHandler &&row_handler, FinishHandler &&finish_handler)
+ {
+ query_explicit(query_text, text_length, detail::make_values(row_handler), std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
+ }
+ template <typename RowHandler, typename FinishHandler>
+ void query(const char *query_text, RowHandler &&row_handler, FinishHandler &&finish_handler)
+ {
+ query_explicit(query_text, detail::make_values(row_handler), std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
+ }
+ template <typename RowHandler, typename FinishHandler>
+ void query(const std::string &query_text, RowHandler &&row_handler, FinishHandler &&finish_handler)
+ {
+ query_explicit(query_text, detail::make_values(row_handler), std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
+ }
- template<typename Params, typename FinishHandler, typename... RowHandlers>
- void query_multi_with_params(const char* query_text, size_t text_length, const Params& params, FinishHandler&& finish_handler, RowHandlers&&... row_handlers)
- {
- T* pThis = static_cast<T*>(this);
- pThis->open_command(query_text, text_length, [params, finish_handler, row_handlers...](const typename T::exception_type& e, const std::shared_ptr<Command>& command) mutable {
+ template <typename Params, typename FinishHandler, typename... RowHandlers>
+ void query_multi_with_params(const char *query_text, size_t text_length, const Params ¶ms, FinishHandler &&finish_handler, RowHandlers &&...row_handlers)
+ {
+ T *pThis = static_cast<T *>(this);
+ pThis->open_command(query_text, text_length, [params, finish_handler, row_handlers...](const typename T::exception_type &e, const std::shared_ptr<Command> &command) mutable
+ {
if (e)
{
finish_handler(e);
@@ -366,38 +365,37 @@
else
qtl::detail::async_fetch_command<typename T::exception_type>(command, std::forward<FinishHandler>(finish_handler), std::forward<RowHandlers>(row_handlers)...);
});
- }
- });
- }
- template<typename Params, typename FinishHandler, typename... RowHandlers>
- void query_multi_with_params(const char* query_text, const Params& params, FinishHandler&& finish_handler, RowHandlers&&... row_handlers)
- {
- query_multi_with_params(query_text, strlen(query_text), params, std::forward<FinishHandler>(finish_handler), std::forward<RowHandlers>(row_handlers)...);
- }
- template<typename Params, typename FinishHandler, typename... RowHandlers>
- void query_multi_with_params(const std::string& query_text, const Params& params, FinishHandler&& finish_handler, RowHandlers&&... row_handlers)
- {
- query_multi_with_params(query_text.data(), query_text.size(), params, std::forward<FinishHandler>(finish_handler), std::forward<RowHandlers>(row_handlers)...);
- }
- template<typename FinishHandler, typename... RowHandlers>
- void query_multi(const char* query_text, size_t text_length, FinishHandler&& finish_handler, RowHandlers&&... row_handlers)
- {
- query_multi_with_params<std::tuple<>, FinishHandler, RowHandlers...>(query_text, text_length, std::make_tuple(), std::forward<FinishHandler>(finish_handler), std::forward<RowHandlers>(row_handlers)...);
- }
- template<typename FinishHandler, typename... RowHandlers>
- void query_multi(const char* query_text, FinishHandler&& finish_handler, RowHandlers&&... row_handlers)
- {
- query_multi_with_params<std::tuple<>, FinishHandler, RowHandlers...>(query_text, strlen(query_text), std::make_tuple(), std::forward<FinishHandler>(finish_handler), std::forward<RowHandlers>(row_handlers)...);
- }
- template<typename FinishHandler, typename... RowHandlers>
- void query_multi(const std::string& query_text, FinishHandler&& finish_handler, RowHandlers&&... row_handlers)
- {
- query_multi_with_params<std::tuple<>, FinishHandler, RowHandlers...>(query_text.data(), query_text.size(), std::make_tuple(), std::forward<FinishHandler>(finish_handler), std::forward<RowHandlers>(row_handlers)...);
- }
+ } });
+ }
+ template <typename Params, typename FinishHandler, typename... RowHandlers>
+ void query_multi_with_params(const char *query_text, const Params ¶ms, FinishHandler &&finish_handler, RowHandlers &&...row_handlers)
+ {
+ query_multi_with_params(query_text, strlen(query_text), params, std::forward<FinishHandler>(finish_handler), std::forward<RowHandlers>(row_handlers)...);
+ }
+ template <typename Params, typename FinishHandler, typename... RowHandlers>
+ void query_multi_with_params(const std::string &query_text, const Params ¶ms, FinishHandler &&finish_handler, RowHandlers &&...row_handlers)
+ {
+ query_multi_with_params(query_text.data(), query_text.size(), params, std::forward<FinishHandler>(finish_handler), std::forward<RowHandlers>(row_handlers)...);
+ }
+ template <typename FinishHandler, typename... RowHandlers>
+ void query_multi(const char *query_text, size_t text_length, FinishHandler &&finish_handler, RowHandlers &&...row_handlers)
+ {
+ query_multi_with_params<std::tuple<>, FinishHandler, RowHandlers...>(query_text, text_length, std::make_tuple(), std::forward<FinishHandler>(finish_handler), std::forward<RowHandlers>(row_handlers)...);
+ }
+ template <typename FinishHandler, typename... RowHandlers>
+ void query_multi(const char *query_text, FinishHandler &&finish_handler, RowHandlers &&...row_handlers)
+ {
+ query_multi_with_params<std::tuple<>, FinishHandler, RowHandlers...>(query_text, strlen(query_text), std::make_tuple(), std::forward<FinishHandler>(finish_handler), std::forward<RowHandlers>(row_handlers)...);
+ }
+ template <typename FinishHandler, typename... RowHandlers>
+ void query_multi(const std::string &query_text, FinishHandler &&finish_handler, RowHandlers &&...row_handlers)
+ {
+ query_multi_with_params<std::tuple<>, FinishHandler, RowHandlers...>(query_text.data(), query_text.size(), std::make_tuple(), std::forward<FinishHandler>(finish_handler), std::forward<RowHandlers>(row_handlers)...);
+ }
-protected:
- qtl::event* m_event_handler { nullptr };
-};
+ protected:
+ qtl::event *m_event_handler{nullptr};
+ };
}
diff --git a/include/qtl_common.hpp b/include/qtl_common.hpp
index 7435d23..b56d2ea 100644
--- a/include/qtl_common.hpp
+++ b/include/qtl_common.hpp
@@ -1,15 +1,15 @@
#ifndef _QTL_COMMON_H_
#define _QTL_COMMON_H_
-#if __cplusplus<201103L && _MSC_VER<1800
+#if __cplusplus < 201103L && _MSC_VER < 1800
#error QTL need C++11 compiler
-#endif //C++11
+#endif // C++11
-#if _MSC_VER>=1800 && _MSC_VER<1900
+#if _MSC_VER >= 1800 && _MSC_VER < 1900
#define NOEXCEPT throw()
#else
#define NOEXCEPT noexcept
-#endif //NOEXCEPT
+#endif // NOEXCEPT
#include <stdint.h>
#include <string.h>
@@ -31,1426 +31,1457 @@
namespace qtl
{
-struct null { };
-
-struct blob_data
-{
- void* data;
- size_t size;
-
- blob_data() : data(NULL), size(0) { }
- blob_data(void* d, size_t n) : data(d), size(n) { }
-};
-
-struct const_blob_data
-{
- const void* data;
- size_t size;
-
- const_blob_data() : data(NULL), size(0) { }
- const_blob_data(const void* d, size_t n) : data(d), size(n) { }
-};
-
-const size_t blob_buffer_size=64*1024;
-
-inline std::string& trim_string(std::string& str, const char* target)
-{
- str.erase(0, str.find_first_not_of(target));
- str.erase(str.find_last_not_of(target)+1);
- return str;
-}
-
-template<typename T>
-struct indicator
-{
- typedef T data_type;
-
- data_type data;
- size_t length;
- bool is_null;
- bool is_truncated;
-
- indicator()
- : is_null(false), is_truncated(false), length(0) { }
- explicit indicator(const data_type& src)
- : is_null(false), is_truncated(false), length(0), data(src) { }
- explicit indicator(data_type&& src)
- : is_null(false), is_truncated(false), length(0), data(std::move(src)) { }
-
- operator bool() const { return is_null; }
- operator data_type&() { return data; }
- operator const data_type&() const { return data; }
-};
-
-template<typename StringT>
-struct bind_string_helper
-{
- typedef StringT string_type;
- typedef typename string_type::value_type char_type;
- bind_string_helper(string_type&& value) : m_value(std::forward<string_type>(value)) { }
- bind_string_helper(const bind_string_helper& src)
- : m_value(std::forward<StringT>(src.m_value))
+ struct null
{
+ };
+
+ struct blob_data
+ {
+ void *data;
+ size_t size;
+
+ blob_data() : data(NULL), size(0) {}
+ blob_data(void *d, size_t n) : data(d), size(n) {}
+ };
+
+ struct const_blob_data
+ {
+ const void *data;
+ size_t size;
+
+ const_blob_data() : data(NULL), size(0) {}
+ const_blob_data(const void *d, size_t n) : data(d), size(n) {}
+ };
+
+ const size_t blob_buffer_size = 64 * 1024;
+
+ inline std::string &trim_string(std::string &str, const char *target)
+ {
+ str.erase(0, str.find_first_not_of(target));
+ str.erase(str.find_last_not_of(target) + 1);
+ return str;
}
- bind_string_helper(bind_string_helper&& src)
- : m_value(std::forward<StringT>(src.m_value))
+
+ template <typename T>
+ struct indicator
{
- }
- bind_string_helper& operator=(const bind_string_helper& src)
+ typedef T data_type;
+
+ data_type data;
+ size_t length;
+ bool is_null;
+ bool is_truncated;
+
+ indicator()
+ : is_null(false), is_truncated(false), length(0) {}
+ explicit indicator(const data_type &src)
+ : is_null(false), is_truncated(false), length(0), data(src) {}
+ explicit indicator(data_type &&src)
+ : is_null(false), is_truncated(false), length(0), data(std::move(src)) {}
+
+ operator bool() const { return is_null; }
+ operator data_type &() { return data; }
+ operator const data_type &() const { return data; }
+ };
+
+ template <typename StringT>
+ struct bind_string_helper
{
- if (this != &src)
+ typedef StringT string_type;
+ typedef typename string_type::value_type char_type;
+ bind_string_helper(string_type &&value) : m_value(std::forward<string_type>(value)) {}
+ bind_string_helper(const bind_string_helper &src)
+ : m_value(std::forward<StringT>(src.m_value))
{
- m_value = std::forward<StringT>(src.m_value);
}
- return *this;
- }
- bind_string_helper& operator=(bind_string_helper&& src)
- {
- if (this != &src)
+ bind_string_helper(bind_string_helper &&src)
+ : m_value(std::forward<StringT>(src.m_value))
{
- m_value = std::forward<StringT>(src.m_value);
}
- return *this;
+ bind_string_helper &operator=(const bind_string_helper &src)
+ {
+ if (this != &src)
+ {
+ m_value = std::forward<StringT>(src.m_value);
+ }
+ return *this;
+ }
+ bind_string_helper &operator=(bind_string_helper &&src)
+ {
+ if (this != &src)
+ {
+ m_value = std::forward<StringT>(src.m_value);
+ }
+ return *this;
+ }
+
+ void clear() { m_value.clear(); }
+ char_type *alloc(size_t n)
+ {
+ m_value.resize(n);
+ return (char_type *)m_value.data();
+ }
+ void truncate(size_t n) { m_value.resize(n); }
+ void assign(const char_type *str, size_t n) { m_value.assign(str, n); }
+ const char_type *data() const { return m_value.data(); }
+ size_t size() const { return m_value.size(); }
+
+ private:
+ string_type &&m_value;
+ };
+
+ template <typename StringT>
+ inline bind_string_helper<typename std::decay<StringT>::type> bind_string(StringT &&value)
+ {
+ typedef typename std::decay<StringT>::type string_type;
+ return bind_string_helper<string_type>(std::forward<string_type>(value));
}
- void clear() { m_value.clear(); }
- char_type* alloc(size_t n) { m_value.resize(n); return (char_type*)m_value.data(); }
- void truncate(size_t n) { m_value.resize(n); }
- void assign(const char_type* str, size_t n) { m_value.assign(str, n); }
- const char_type* data() const { return m_value.data(); }
- size_t size() const { return m_value.size(); }
-private:
- string_type&& m_value;
-};
+ template <typename Command>
+ inline void bind_param(Command &command, size_t index, const std::string ¶m)
+ {
+ command.bind_param(index, param.data(), param.size());
+ }
-template<typename StringT>
-inline bind_string_helper<typename std::decay<StringT>::type> bind_string(StringT&& value)
-{
- typedef typename std::decay<StringT>::type string_type;
- return bind_string_helper<string_type>(std::forward<string_type>(value));
-}
+ template <typename Command>
+ inline void bind_param(Command &command, size_t index, std::istream ¶m)
+ {
+ command.bind_param(index, param);
+ }
-template<typename Command>
-inline void bind_param(Command& command, size_t index, const std::string& param)
-{
- command.bind_param(index, param.data(), param.size());
-}
-
-template<typename Command>
-inline void bind_param(Command& command, size_t index, std::istream& param)
-{
- command.bind_param(index, param);
-}
-
-template<typename Command, typename T>
-inline void bind_param(Command& command, size_t index, const T& param)
-{
- command.bind_param(index, param);
-}
+ template <typename Command, typename T>
+ inline void bind_param(Command &command, size_t index, const T ¶m)
+ {
+ command.bind_param(index, param);
+ }
#ifdef _QTL_ENABLE_CPP17
-template<typename Command, typename T>
-inline void bind_param(Command& command, size_t index, const std::optional<T>& param)
-{
- if(param)
- command.bind_param(index, *param);
- else
- command.bind_param(index, nullptr);
-}
+ template <typename Command, typename T>
+ inline void bind_param(Command &command, size_t index, const std::optional<T> ¶m)
+ {
+ if (param)
+ command.bind_param(index, *param);
+ else
+ command.bind_param(index, nullptr);
+ }
#endif // C++17
-// The order of the overloaded functions 'bind_field' is very important
-// The version with the most generic parameters is at the end
+ // The order of the overloaded functions 'bind_field' is very important
+ // The version with the most generic parameters is at the end
-template<typename Command, size_t N>
-inline void bind_field(Command& command, size_t index, char (&value)[N])
-{
- command.bind_field(index, value, N);
-}
+ template <typename Command, size_t N>
+ inline void bind_field(Command &command, size_t index, char (&value)[N])
+ {
+ command.bind_field(index, value, N);
+ }
-template<typename Command, size_t N>
-inline void bind_field(Command& command, size_t index, wchar_t (&value)[N])
-{
- command.bind_field(index, value, N);
-}
+ template <typename Command, size_t N>
+ inline void bind_field(Command &command, size_t index, wchar_t (&value)[N])
+ {
+ command.bind_field(index, value, N);
+ }
-template<typename Command>
-inline void bind_field(Command& command, size_t index, char* value, size_t length)
-{
- command.bind_field(index, value, length);
-}
+ template <typename Command>
+ inline void bind_field(Command &command, size_t index, char *value, size_t length)
+ {
+ command.bind_field(index, value, length);
+ }
-template<typename Command>
-inline void bind_field(Command& command, size_t index, wchar_t* value, size_t length)
-{
- command.bind_field(index, value, length);
-}
+ template <typename Command>
+ inline void bind_field(Command &command, size_t index, wchar_t *value, size_t length)
+ {
+ command.bind_field(index, value, length);
+ }
-template<typename Command>
-inline void bind_field(Command& command, size_t index, std::string&& value)
-{
- command.bind_field(index, bind_string(std::forward<std::string>(value)));
-}
+ template <typename Command>
+ inline void bind_field(Command &command, size_t index, std::string &&value)
+ {
+ command.bind_field(index, bind_string(std::forward<std::string>(value)));
+ }
-template<typename Command>
-inline void bind_field(Command& command, size_t index, std::wstring&& value)
-{
- command.bind_field(index, bind_string(std::forward<std::wstring>(value)));
-}
+ template <typename Command>
+ inline void bind_field(Command &command, size_t index, std::wstring &&value)
+ {
+ command.bind_field(index, bind_string(std::forward<std::wstring>(value)));
+ }
-template<typename Command>
-inline void bind_field(Command& command, size_t index, std::vector<char>&& value)
-{
- command.bind_field(index, bind_string(std::forward<std::vector<char>>(value)));
-}
+ template <typename Command>
+ inline void bind_field(Command &command, size_t index, std::vector<char> &&value)
+ {
+ command.bind_field(index, bind_string(std::forward<std::vector<char>>(value)));
+ }
-template<typename Command>
-inline void bind_field(Command& command, size_t index, std::vector<wchar_t>&& value)
-{
- command.bind_field(index, bind_string(std::forward<std::vector<wchar_t>>(value)));
-}
+ template <typename Command>
+ inline void bind_field(Command &command, size_t index, std::vector<wchar_t> &&value)
+ {
+ command.bind_field(index, bind_string(std::forward<std::vector<wchar_t>>(value)));
+ }
-template<typename Command, typename T, typename=typename std::enable_if<!std::is_reference<T>::value>::type>
-inline void bind_field(Command& command, size_t index, T&& value)
-{
- command.bind_field(index, std::forward<T>(value));
-}
-
-template<typename Command, typename T>
-inline void bind_field(Command& command, size_t index, T& value)
-{
- bind_field(command, index, std::forward<T>(value));
-}
-
-template<typename Command, typename T, typename=typename std::enable_if<!std::is_reference<T>::value>::type>
-inline void bind_field(Command& command, const char* name, T&& value)
-{
- size_t index=command.find_field(name);
- if(index==-1)
- value=T();
- else
+ template <typename Command, typename T, typename = typename std::enable_if<!std::is_reference<T>::value>::type>
+ inline void bind_field(Command &command, size_t index, T &&value)
+ {
command.bind_field(index, std::forward<T>(value));
-}
+ }
-template<typename Command, typename T>
-inline void bind_field(Command& command, const char* name, T& value)
-{
- size_t index=command.find_field(name);
- if(index==-1)
- value=T();
- else
+ template <typename Command, typename T>
+ inline void bind_field(Command &command, size_t index, T &value)
+ {
bind_field(command, index, std::forward<T>(value));
-}
-
-template<typename Command>
-inline void bind_field(Command& command, const char* name, char* value, size_t length)
-{
- size_t index=command.find_field(name);
- if (index == -1)
- {
- if (length > 0) value[0] = '\0';
}
- else
- command.bind_field(index, value, length);
-}
-template<typename Command>
-inline void bind_field(Command& command, const char* name, wchar_t* value, size_t length)
-{
- size_t index=command.find_field(name);
- if (index == -1)
+ template <typename Command, typename T, typename = typename std::enable_if<!std::is_reference<T>::value>::type>
+ inline void bind_field(Command &command, const char *name, T &&value)
{
- if (length > 0) value[0] = '\0';
+ size_t index = command.find_field(name);
+ if (index == -1)
+ value = T();
+ else
+ command.bind_field(index, std::forward<T>(value));
}
- else
- command.bind_field(index, value, length);
-}
-template<typename Command, typename T>
-inline void bind_field(Command& command, const char* name, std::reference_wrapper<T>&& value)
-{
- return bind_field(command, value.get());
-}
+ template <typename Command, typename T>
+ inline void bind_field(Command &command, const char *name, T &value)
+ {
+ size_t index = command.find_field(name);
+ if (index == -1)
+ value = T();
+ else
+ bind_field(command, index, std::forward<T>(value));
+ }
+
+ template <typename Command>
+ inline void bind_field(Command &command, const char *name, char *value, size_t length)
+ {
+ size_t index = command.find_field(name);
+ if (index == -1)
+ {
+ if (length > 0)
+ value[0] = '\0';
+ }
+ else
+ command.bind_field(index, value, length);
+ }
+
+ template <typename Command>
+ inline void bind_field(Command &command, const char *name, wchar_t *value, size_t length)
+ {
+ size_t index = command.find_field(name);
+ if (index == -1)
+ {
+ if (length > 0)
+ value[0] = '\0';
+ }
+ else
+ command.bind_field(index, value, length);
+ }
+
+ template <typename Command, typename T>
+ inline void bind_field(Command &command, const char *name, std::reference_wrapper<T> &&value)
+ {
+ return bind_field(command, value.get());
+ }
#ifdef _QTL_ENABLE_CPP17
-template<typename Command, typename T>
-inline void bind_field(Command& command, size_t index, std::optional<T>& value)
-{
- value.emplace();
- command.bind_field(index, std::forward<T>(value));
-}
+ template <typename Command, typename T>
+ inline void bind_field(Command &command, size_t index, std::optional<T> &value)
+ {
+ value.emplace();
+ command.bind_field(index, std::forward<T>(value));
+ }
-template<typename Command, typename T>
-inline void bind_field(Command& command, const char* name, std::optional<T>& value)
-{
- size_t index = command.find_field(name);
- if (index == -1)
- value.reset();
- else
- bind_field(command, index, value);
-}
+ template <typename Command, typename T>
+ inline void bind_field(Command &command, const char *name, std::optional<T> &value)
+ {
+ size_t index = command.find_field(name);
+ if (index == -1)
+ value.reset();
+ else
+ bind_field(command, index, value);
+ }
#endif // C++17
-template<typename Command, typename T>
-inline size_t bind_fields(Command& command, size_t index, T&& value)
-{
- bind_field(command, index, std::forward<T>(value));
- return index+1;
-}
+ template <typename Command, typename T>
+ inline size_t bind_fields(Command &command, size_t index, T &&value)
+ {
+ bind_field(command, index, std::forward<T>(value));
+ return index + 1;
+ }
-template<typename Command, typename T, typename... Other>
-inline size_t bind_fields(Command& command, size_t start, T&& value, Other&&... other)
-{
- bind_field(command, start, std::forward<T>(value));
- return bind_fields(command, start+1, std::forward<Other>(other)...);
-}
+ template <typename Command, typename T, typename... Other>
+ inline size_t bind_fields(Command &command, size_t start, T &&value, Other &&...other)
+ {
+ bind_field(command, start, std::forward<T>(value));
+ return bind_fields(command, start + 1, std::forward<Other>(other)...);
+ }
-template<typename Command, typename... Fields>
-inline size_t bind_fields(Command& command, Fields&&... fields)
-{
- return bind_fields(command, (size_t)0, std::forward<Fields>(fields)...);
-}
+ template <typename Command, typename... Fields>
+ inline size_t bind_fields(Command &command, Fields &&...fields)
+ {
+ return bind_fields(command, (size_t)0, std::forward<Fields>(fields)...);
+ }
-namespace detail
-{
+ namespace detail
+ {
-template<typename F, typename T>
-struct apply_impl
-{
-private:
+ template <typename F, typename T>
+ struct apply_impl
+ {
+ private:
#if __cplusplus >= 202002L || _MSVC_LANG >= 202002L
- typedef typename std::invoke_result<F, T>::type raw_result_type;
+ typedef typename std::invoke_result<F, T>::type raw_result_type;
#else
- typedef typename std::result_of<F(T)>::type raw_result_type;
+ typedef typename std::result_of<F(T)>::type raw_result_type;
#endif
- template<typename Ret, bool>
- struct impl {};
- template<typename Ret>
- struct impl<Ret, true>
- {
- typedef bool result_type;
- result_type operator()(F&& f, T&& v)
- {
- f(std::forward<T>(v));
- return true;
- }
- };
- template<typename Ret>
- struct impl<Ret, false>
- {
- typedef Ret result_type;
- result_type operator()(F&& f, T&& v)
- {
- return f(std::forward<T>(v));
- }
- };
+ template <typename Ret, bool>
+ struct impl
+ {
+ };
+ template <typename Ret>
+ struct impl<Ret, true>
+ {
+ typedef bool result_type;
+ result_type operator()(F &&f, T &&v)
+ {
+ f(std::forward<T>(v));
+ return true;
+ }
+ };
+ template <typename Ret>
+ struct impl<Ret, false>
+ {
+ typedef Ret result_type;
+ result_type operator()(F &&f, T &&v)
+ {
+ return f(std::forward<T>(v));
+ }
+ };
-public:
- typedef typename impl<raw_result_type, std::is_void<raw_result_type>::value>::result_type result_type;
- result_type operator()(F&& f, T&& v)
- {
- return impl<raw_result_type, std::is_void<raw_result_type>::value>()(std::forward<F>(f), std::forward<T>(v));
- }
-};
+ public:
+ typedef typename impl<raw_result_type, std::is_void<raw_result_type>::value>::result_type result_type;
+ result_type operator()(F &&f, T &&v)
+ {
+ return impl<raw_result_type, std::is_void<raw_result_type>::value>()(std::forward<F>(f), std::forward<T>(v));
+ }
+ };
-template<typename F, typename... Types>
-struct apply_impl<F, std::tuple<Types...>>
-{
-private:
- typedef typename std::remove_reference<F>::type fun_type;
- typedef std::tuple<Types...> arg_type;
+ template <typename F, typename... Types>
+ struct apply_impl<F, std::tuple<Types...>>
+ {
+ private:
+ typedef typename std::remove_reference<F>::type fun_type;
+ typedef std::tuple<Types...> arg_type;
#if __cplusplus >= 202002L || _MSVC_LANG >= 202002L
- typedef typename std::invoke_result<F, Types...>::type raw_result_type;
+ typedef typename std::invoke_result<F, Types...>::type raw_result_type;
#else
- typedef typename std::result_of<F(Types...)>::type raw_result_type;
+ typedef typename std::result_of<F(Types...)>::type raw_result_type;
#endif
- template<typename Ret, bool>
- struct impl {};
- template<typename Ret>
- struct impl<Ret, true>
- {
- typedef bool result_type;
- result_type operator()(F&& f, arg_type&& v)
+ template <typename Ret, bool>
+ struct impl
+ {
+ };
+ template <typename Ret>
+ struct impl<Ret, true>
+ {
+ typedef bool result_type;
+ result_type operator()(F &&f, arg_type &&v)
+ {
+ qtl::detail::apply_tuple(std::forward<F>(f), std::forward<arg_type>(v));
+ return true;
+ }
+ };
+ template <typename Ret>
+ struct impl<Ret, false>
+ {
+ typedef Ret result_type;
+ result_type operator()(F &&f, arg_type &&v)
+ {
+ return qtl::detail::apply_tuple(std::forward<F>(f), std::forward<arg_type>(v));
+ }
+ };
+
+ public:
+ typedef typename impl<raw_result_type, std::is_void<raw_result_type>::value>::result_type result_type;
+ result_type operator()(F &&f, arg_type &&v)
+ {
+ return impl<raw_result_type, std::is_void<raw_result_type>::value>()(std::forward<F>(f), std::forward<arg_type>(v));
+ }
+ };
+
+ template <typename Type, typename R>
+ struct apply_impl<R (Type::*)(), Type>
{
- qtl::detail::apply_tuple(std::forward<F>(f), std::forward<arg_type>(v));
- return true;
- }
- };
- template<typename Ret>
- struct impl<Ret, false>
- {
- typedef Ret result_type;
- result_type operator()(F&& f, arg_type&& v)
+ private:
+ typedef R (Type::*fun_type)();
+ typedef R raw_result_type;
+ template <typename Ret, bool>
+ struct impl
+ {
+ };
+ template <typename Ret>
+ struct impl<Ret, true>
+ {
+ typedef bool result_type;
+ result_type operator()(fun_type f, Type &&v)
+ {
+ (v.*f)();
+ return true;
+ }
+ };
+ template <typename Ret>
+ struct impl<Ret, false>
+ {
+ typedef Ret result_type;
+ result_type operator()(fun_type f, Type &&v)
+ {
+ return (v.*f)();
+ }
+ };
+
+ public:
+ typedef typename impl<raw_result_type, std::is_void<raw_result_type>::value>::result_type result_type;
+ result_type operator()(R (Type::*f)(), Type &&v)
+ {
+ return impl<raw_result_type, std::is_void<raw_result_type>::value>()(f, std::forward<Type>(v));
+ }
+ };
+
+ template <typename Type, typename R>
+ struct apply_impl<R (Type::*)() const, Type>
{
- return qtl::detail::apply_tuple(std::forward<F>(f), std::forward<arg_type>(v));
- }
- };
+ private:
+ typedef R (Type::*fun_type)() const;
+ typedef R raw_result_type;
+ template <typename Ret, bool>
+ struct impl
+ {
+ };
+ template <typename Ret>
+ struct impl<Ret, true>
+ {
+ typedef bool result_type;
+ result_type operator()(fun_type f, Type &&v)
+ {
+ (v.*f)();
+ return true;
+ }
+ };
+ template <typename Ret>
+ struct impl<Ret, false>
+ {
+ typedef Ret result_type;
+ result_type operator()(fun_type f, Type &&v)
+ {
+ return (v.*f)();
+ }
+ };
-public:
- typedef typename impl<raw_result_type, std::is_void<raw_result_type>::value>::result_type result_type;
- result_type operator()(F&& f, arg_type&& v)
- {
- return impl<raw_result_type, std::is_void<raw_result_type>::value>()(std::forward<F>(f), std::forward<arg_type>(v));
- }
-};
+ public:
+ typedef typename impl<raw_result_type, std::is_void<raw_result_type>::value>::result_type result_type;
+ result_type operator()(fun_type f, Type &&v)
+ {
+ return impl<raw_result_type, std::is_void<raw_result_type>::value>()(f, std::forward<Type>(v));
+ }
+ };
-template<typename Type, typename R>
-struct apply_impl<R (Type::*)(), Type>
-{
-private:
- typedef R (Type::*fun_type)();
- typedef R raw_result_type;
- template<typename Ret, bool>
- struct impl {};
- template<typename Ret>
- struct impl<Ret, true>
- {
- typedef bool result_type;
- result_type operator()(fun_type f, Type&& v)
+ template <typename F, typename T>
+ typename apply_impl<F, T>::result_type apply(F &&f, T &&v)
{
- (v.*f)();
- return true;
+ return apply_impl<F, T>()(std::forward<F>(f), std::forward<T>(v));
}
- };
- template<typename Ret>
- struct impl<Ret, false>
- {
- typedef Ret result_type;
- result_type operator()(fun_type f, Type&& v)
+
+ template <typename Command, size_t N, typename... Types>
+ struct bind_helper
{
- return (v.*f)();
- }
- };
+ public:
+ explicit bind_helper(Command &command) : m_command(command) {}
+ void operator()(const std::tuple<Types...> ¶ms) const
+ {
+ bind_param(m_command, N - 1, std::get<N - 1>(params));
+ (bind_helper<Command, N - 1, Types...>(m_command))(params);
+ }
+ void operator()(std::tuple<Types...> &¶ms) const
+ {
+ typedef typename std::remove_reference<typename std::tuple_element<N - 1, tuple_type>::type>::type param_type;
+ bind_field(m_command, N - 1, std::forward<param_type>(std::get<N - 1>(std::forward<tuple_type>(params))));
+ (bind_helper<Command, N - 1, Types...>(m_command))(std::forward<tuple_type>(params));
+ }
-public:
- typedef typename impl<raw_result_type, std::is_void<raw_result_type>::value>::result_type result_type;
- result_type operator()(R (Type::*f)(), Type&& v)
- {
- return impl<raw_result_type, std::is_void<raw_result_type>::value>()(f, std::forward<Type>(v));
- }
-};
+ private:
+ typedef std::tuple<Types...> tuple_type;
+ Command &m_command;
+ };
-template<typename Type, typename R>
-struct apply_impl<R (Type::*)() const, Type>
-{
-private:
- typedef R (Type::*fun_type)() const;
- typedef R raw_result_type;
- template<typename Ret, bool>
- struct impl {};
- template<typename Ret>
- struct impl<Ret, true>
- {
- typedef bool result_type;
- result_type operator()(fun_type f, Type&& v)
+ template <typename Command, typename... Types>
+ struct bind_helper<Command, 1, Types...>
{
- (v.*f)();
- return true;
- }
- };
- template<typename Ret>
- struct impl<Ret, false>
- {
- typedef Ret result_type;
- result_type operator()(fun_type f, Type&& v)
+ public:
+ explicit bind_helper(Command &command) : m_command(command) {}
+ void operator()(const std::tuple<Types...> ¶ms) const
+ {
+ bind_param(m_command, 0, std::get<0>(params));
+ }
+ void operator()(std::tuple<Types...> &¶ms) const
+ {
+ typedef typename std::remove_reference<typename std::tuple_element<0, tuple_type>::type>::type param_type;
+ bind_field(m_command, static_cast<size_t>(0), std::forward<param_type>(std::get<0>(std::forward<tuple_type>(params))));
+ }
+
+ private:
+ typedef std::tuple<Types...> tuple_type;
+ Command &m_command;
+ };
+
+ template <typename Command, typename... Types>
+ struct bind_helper<Command, 0, Types...>
{
- return (v.*f)();
- }
- };
-
-public:
- typedef typename impl<raw_result_type, std::is_void<raw_result_type>::value>::result_type result_type;
- result_type operator()(fun_type f, Type&& v)
- {
- return impl<raw_result_type, std::is_void<raw_result_type>::value>()(f, std::forward<Type>(v));
- }
-};
-
-template<typename F, typename T>
-typename apply_impl<F, T>::result_type apply(F&& f, T&& v)
-{
- return apply_impl<F, T>()(std::forward<F>(f), std::forward<T>(v));
-}
-
-template<typename Command, size_t N, typename... Types>
-struct bind_helper
-{
-public:
- explicit bind_helper(Command& command) : m_command(command) { }
- void operator()(const std::tuple<Types...>& params) const
- {
- bind_param(m_command, N-1, std::get<N-1>(params));
- (bind_helper<Command, N-1, Types...>(m_command))(params);
- }
- void operator()(std::tuple<Types...>&& params) const
- {
- typedef typename std::remove_reference<typename std::tuple_element<N-1, tuple_type>::type>::type param_type;
- bind_field(m_command, N-1, std::forward<param_type>(std::get<N-1>(std::forward<tuple_type>(params))));
- (bind_helper<Command, N-1, Types...>(m_command))(std::forward<tuple_type>(params));
- }
-private:
- typedef std::tuple<Types...> tuple_type;
- Command& m_command;
-};
-
-template<typename Command, typename... Types>
-struct bind_helper<Command, 1, Types...>
-{
-public:
- explicit bind_helper(Command& command) : m_command(command) { }
- void operator()(const std::tuple<Types...>& params) const
- {
- bind_param(m_command, 0, std::get<0>(params));
- }
- void operator()(std::tuple<Types...>&& params) const
- {
- typedef typename std::remove_reference<typename std::tuple_element<0, tuple_type>::type>::type param_type;
- bind_field(m_command, static_cast<size_t>(0), std::forward<param_type>(std::get<0>(std::forward<tuple_type>(params))));
- }
-private:
- typedef std::tuple<Types...> tuple_type;
- Command& m_command;
-};
-
-template<typename Command, typename... Types>
-struct bind_helper<Command, 0, Types...>
-{
-public:
- explicit bind_helper(Command& command) { }
- void operator()(const std::tuple<Types...>& params) const
- {
- }
- void operator()(std::tuple<Types...>&& params) const
- {
- }
-};
+ public:
+ explicit bind_helper(Command &command) {}
+ void operator()(const std::tuple<Types...> ¶ms) const
+ {
+ }
+ void operator()(std::tuple<Types...> &¶ms) const
+ {
+ }
+ };
#define QTL_ARGS_TUPLE(Arg, Others) \
typename std::tuple<typename std::decay<Arg>::type, typename std::decay<Others>::type...>
-template<typename Ret, typename Arg>
-inline typename std::decay<Arg>::type make_values(Ret (*)(Arg))
-{
- return typename std::decay<Arg>::type();
-};
-
-template<typename Ret, typename Arg, typename... Others>
-inline auto make_values(Ret (*)(Arg, Others...)) -> QTL_ARGS_TUPLE(Arg, Others)
-{
- return QTL_ARGS_TUPLE(Arg, Others)();
-};
-
-template<typename Type, typename Ret>
-inline Type make_values(Ret (Type::*)())
-{
- return Type();
-};
-template<typename Type, typename Ret>
-inline Type make_values(Ret (Type::*)() const)
-{
- return Type();
-};
-
-template<typename Type, typename Ret, typename... Args>
-inline auto make_values(Ret (Type::*)(Args...)) -> QTL_ARGS_TUPLE(Type, Args)
-{
- return QTL_ARGS_TUPLE(Type, Args)();
-};
-template<typename Type, typename Ret, typename... Args>
-inline auto make_values(Ret (Type::*)(Args...) const) -> QTL_ARGS_TUPLE(Type, Args)
-{
- return QTL_ARGS_TUPLE(Type, Args)();
-};
-
-template<typename Type, typename Ret, typename Arg>
-inline typename std::decay<Arg>::type make_values_noclass(Ret (Type::*)(Arg))
-{
- return typename std::decay<Arg>::type();
-};
-template<typename Type, typename Ret, typename Arg>
-inline typename std::decay<Arg>::type make_values_noclass(Ret (Type::*)(Arg) const)
-{
- return typename std::decay<Arg>::type();
-};
-
-template<typename Type, typename Ret, typename Arg, typename... Others>
-inline auto make_values_noclass(Ret (Type::*)(Arg, Others...)) -> QTL_ARGS_TUPLE(Arg, Others)
-{
- return QTL_ARGS_TUPLE(Arg, Others)();
-};
-template<typename Type, typename Ret, typename Arg, typename... Others>
-inline auto make_values_noclass(Ret (Type::*)(Arg, Others...) const) -> QTL_ARGS_TUPLE(Arg, Others)
-{
- return QTL_ARGS_TUPLE(Arg, Others)();
-};
-
-template<typename Functor, typename=typename std::enable_if<std::is_member_function_pointer<decltype(&Functor::operator())>::value>::type>
-inline auto make_values(const Functor&)
--> decltype(make_values_noclass(&Functor::operator()))
-{
- return make_values_noclass(&Functor::operator());
-}
-
-template<typename Command, typename ValueProc>
-inline void fetch_command(Command& command, ValueProc&& proc)
-{
- auto values=make_values(proc);
- typedef decltype(values) values_type;
- while(command.fetch(std::forward<values_type>(values)))
- {
- if(!apply(std::forward<ValueProc>(proc), std::forward<values_type>(values)))
- break;
- }
-}
-
-template<typename Command, typename ValueProc, typename... OtherProc>
-inline void fetch_command(Command& command, ValueProc&& proc, OtherProc&&... other)
-{
- fetch_command(command, std::forward<ValueProc>(proc));
- if(command.next_result())
- {
- fetch_command(command, std::forward<OtherProc>(other)...);
- }
-}
-
-}
-
-template<typename Command, typename T>
-struct params_binder
-{
- enum { size = 1 };
- inline void operator()(Command& command, const T& param) const
- {
- qtl::bind_param(command, 0, param);
- }
-};
-
-template<typename Command, typename... Types>
-struct params_binder<Command, std::tuple<Types...>>
-{
- enum { size = sizeof...(Types) };
- void operator()(Command& command, const std::tuple<Types...>& params) const
- {
- (detail::bind_helper<Command, std::tuple_size<std::tuple<Types...>>::value, Types...>(command))(params);
- }
-};
-
-template<typename Command, typename Type1, typename Type2>
-struct params_binder<Command, std::pair<Type1, Type2>>
-{
- enum { size = 2 };
- void operator()(Command& command, std::pair<Type1, Type2>&& values) const
- {
- qtl::bind_param(command, 0, std::forward<Type1>(values.first));
- qtl::bind_param(command, 1, std::forward<Type2>(values.second));
- }
-};
-
-template<typename Command, typename T>
-inline void bind_params(Command& command, const T& param)
-{
- params_binder<Command, T> binder;
- binder(command, param);
-}
-
-template<typename Command, typename T>
-struct record_binder
-{
- inline void operator()(Command& command, T&& value) const
- {
- bind_field(command, static_cast<size_t>(0), std::forward<typename std::remove_reference<T>::type>(value));
- }
-};
-
-template<typename Command, typename T>
-struct record_binder<Command, std::reference_wrapper<T>>
-{
- inline void operator()(Command& command, std::reference_wrapper<T>&& value) const
- {
- bind_field(command, static_cast<size_t>(0), std::forward<typename std::remove_reference<T>::type>(value.get()));
- }
-};
-
-template<typename Command, typename... Types>
-struct record_binder<Command, std::tuple<Types...>>
-{
- void operator()(Command& command, std::tuple<Types...>&& values) const
- {
- (detail::bind_helper<Command, std::tuple_size<std::tuple<Types...>>::value, Types...>(command))
- (std::forward<std::tuple<Types...>>(values));
- }
-};
-
-template<typename Command, typename Type1, typename Type2>
-struct record_binder<Command, std::pair<Type1, Type2>>
-{
- void operator()(Command& command, std::pair<Type1, Type2>&& values) const
- {
- bind_field(command, static_cast<size_t>(0), std::forward<Type1>(values.first));
- bind_field(command, static_cast<size_t>(1), std::forward<Type2>(values.second));
- }
-};
-
-template<typename T, typename Tag>
-struct record_with_tag : public T
-{
-};
-
-template<typename T, typename Pred>
-struct custom_binder_type : public T
-{
- typedef T value_type;
-
- explicit custom_binder_type(Pred pred) : m_pred(pred) { }
- custom_binder_type(value_type&& v, Pred pred)
- : value_type(std::forward<value_type>(v)), m_pred(pred)
- {
- }
- template<typename... Args>
- custom_binder_type(Pred pred, Args&&... args)
- : value_type(std::forward<Args>(args)...), m_pred(pred)
- {
- }
-
- template<typename Command>
- void bind(Command& command)
- {
- m_pred(std::forward<T>(*this), command); // Pred maybe member function
- }
-
-private:
- Pred m_pred;
-};
-
-template<typename T, typename Pred>
-struct custom_binder_type<std::reference_wrapper<T>, Pred> : public std::reference_wrapper<T>
-{
- typedef std::reference_wrapper<T> value_type;
-
- explicit custom_binder_type(Pred pred) : m_pred(pred) { }
- custom_binder_type(value_type&& v, Pred pred)
- : value_type(std::forward<value_type>(v)), m_pred(pred)
- {
- }
- template<typename... Args>
- custom_binder_type(Pred pred, Args&&... args)
- : T(std::forward<Args>(args)...), m_pred(pred)
- {
- }
-
- template<typename Command>
- void bind(Command& command)
- {
- m_pred(std::forward<T>(*this), command); // Pred maybe member function
- }
-
-private:
- Pred m_pred;
-};
-
-
-template<typename T, typename Pred>
-inline custom_binder_type<T, Pred> custom_bind(T&& v, Pred pred)
-{
- return custom_binder_type<T, Pred>(std::forward<T>(v), pred);
-}
-
-template<typename Command, typename T, typename Pred>
-struct record_binder<Command, custom_binder_type<T, Pred>>
-{
- void operator()(Command& command, custom_binder_type<T, Pred>&& values) const
- {
- values.bind(command);
- }
-};
-
-template<typename Command, typename T>
-inline void bind_record(Command& command, T&& value)
-{
- record_binder<Command, T> binder;
- binder(command, std::forward<T>(value));
-}
-
-template<typename Command, typename Record>
-class query_iterator final
-{
-public:
- using iterator_category = std::forward_iterator_tag;
- using value_type = Record;
- using difference_type = ptrdiff_t;
- using pointer = Record*;
- using reference = Record&;
-
- explicit query_iterator(Command& command)
- : m_command(command) { }
- Record* operator->() const { return m_record.get(); }
- Record& operator*() const { return *m_record; }
-
- query_iterator& operator++()
- {
- if(!m_record)
- m_record=std::make_shared<Record>();
- if(m_record.use_count()==1)
+ template <typename Ret, typename Arg>
+ inline typename std::decay<Arg>::type make_values(Ret (*)(Arg))
{
- if(!m_command.fetch(std::forward<Record>(*m_record)))
- m_record.reset();
- }
- else
+ return typename std::decay<Arg>::type();
+ };
+
+ template <typename Ret, typename Arg, typename... Others>
+ inline auto make_values(Ret (*)(Arg, Others...)) -> QTL_ARGS_TUPLE(Arg, Others)
{
- std::shared_ptr<Record> record=std::make_shared<Record>();
- if(m_command.fetch(std::forward<Record>(*record)))
- m_record=record;
- else
- m_record.reset();
- }
- return *this;
- }
- query_iterator operator++(int)
- {
- query_iterator temp=*this;
- m_record=std::make_shared<Record>();
- if(!m_command.fetch(std::forward<Record>(*m_record)))
- m_record.reset();
- return temp;
- }
+ return QTL_ARGS_TUPLE(Arg, Others)();
+ };
- bool operator ==(const query_iterator& rhs)
- {
- return &this->m_command==&rhs.m_command &&
- this->m_record==rhs.m_record;
- }
- bool operator !=(const query_iterator& rhs)
- {
- return !(*this==rhs);
- }
-
-private:
- Command& m_command;
- std::shared_ptr<Record> m_record;
-};
-
-template<typename Command, typename Record>
-class query_result final
-{
-public:
- typedef typename query_iterator<Command, Record>::value_type value_type;
- typedef typename query_iterator<Command, Record>::pointer pointer;
- typedef typename query_iterator<Command, Record>::reference reference;
- typedef query_iterator<Command, Record> iterator;
-
- explicit query_result(Command&& command) : m_command(std::move(command)) { }
- query_result(query_result&& src) : m_command(std::move(src.m_command)) { }
- query_result& operator=(query_result&& src)
- {
- if(this!=&src)
- m_command=std::move(src.m_command);
- return *this;
- }
-
- template<typename Params>
- iterator begin(const Params& params)
- {
- query_iterator<Command, Record> it(m_command);
- ++it;
- return it;
- }
- iterator begin()
- {
- return begin(std::make_tuple());
- }
-
- iterator end()
- {
- return query_iterator<Command, Record>(m_command);
- }
-
-private:
- Command m_command;
-};
-
-template<typename T, class Command>
-class base_database
-{
-public:
- template<typename Params>
- base_database& execute(const char* query_text, size_t text_length, const Params& params, uint64_t* affected=NULL)
- {
- T* pThis=static_cast<T*>(this);
- Command command=pThis->open_command(query_text, text_length);
- command.execute(params);
- if(affected) *affected=command.affetced_rows();
- command.close();
- return *this;
- }
- template<typename Params>
- base_database& execute(const char* query_text, const Params& params, uint64_t* affected=NULL)
- {
- return execute(query_text, strlen(query_text), params, affected);
- }
- template<typename Params>
- base_database& execute(const std::string& query_text, const Params& params, uint64_t* affected=NULL)
- {
- return execute(query_text.data(), query_text.length(), params, affected);
- }
-
- template<typename... Params>
- base_database& execute_direct(const char* query_text, size_t text_length, uint64_t* affected, const Params&... params)
- {
- return execute(query_text, text_length, std::forward_as_tuple(params...), affected);
- }
- template<typename... Params>
- base_database& execute_direct(const char* query_text, uint64_t* affected, const Params&... params)
- {
- return execute(query_text, std::forward_as_tuple(params...), affected);
- }
- template<typename... Params>
- base_database& execute_direct(const std::string& query_text, uint64_t* affected, const Params&... params)
- {
- return execute(query_text, std::forward_as_tuple(params...), affected);
- }
-
- template<typename Params>
- uint64_t insert(const char* query_text, size_t text_length, const Params& params)
- {
- uint64_t id=0;
- T* pThis=static_cast<T*>(this);
- Command command=pThis->open_command(query_text, text_length);
- command.execute(params);
- if(command.affetced_rows()>0)
- id=command.insert_id();
- return id;
- }
-
- template<typename Params>
- uint64_t insert(const char* query_text, const Params& params)
- {
- return insert(query_text, strlen(query_text), params);
- }
-
- template<typename Params>
- uint64_t insert(const std::string& query_text, const Params& params)
- {
- return insert(query_text.data(), query_text.length(), params);
- }
-
- template<typename... Params>
- uint64_t insert_direct(const char* query_text, size_t text_length, const Params&... params)
- {
- return insert(query_text, text_length, std::forward_as_tuple(params...));
- }
-
- template<typename... Params>
- uint64_t insert_direct(const char* query_text, const Params&... params)
- {
- return insert(query_text, strlen(query_text), std::forward_as_tuple(params...));
- }
-
- template<typename... Params>
- uint64_t insert_direct(const std::string& query_text, const Params&... params)
- {
- return insert(query_text.data(), query_text.length(), std::forward_as_tuple(params...));
- }
-
- template<typename Record, typename Params>
- query_result<Command, Record> result(const char* query_text, size_t text_length, const Params& params)
- {
- T* pThis=static_cast<T*>(this);
- Command command=pThis->open_command(query_text, text_length);
- command.execute(params);
- return query_result<Command, Record>(std::move(command));
- }
- template<typename Record, typename Params>
- query_result<Command, Record> result(const char* query_text, const Params& params)
- {
- return result<Record, Params>(query_text, strlen(query_text), params);
- }
- template<typename Record, typename Params>
- query_result<Command, Record> result(const std::string& query_text, const Params& params)
- {
- return result<Record, Params>(query_text.data(), query_text.length(), params);
- }
- template<typename Record>
- query_result<Command, Record> result(const char* query_text, size_t text_length)
- {
- return result<Record>(query_text, text_length, std::make_tuple());
- }
- template<typename Record>
- query_result<Command, Record> result(const char* query_text)
- {
- return result<Record>(query_text, strlen(query_text), std::make_tuple());
- }
- template<typename Record>
- query_result<Command, Record> result(const std::string& query_text)
- {
- return result<Record>(query_text.data(), query_text.length(), std::make_tuple());
- }
-
- template<typename Params, typename Values, typename ValueProc>
- base_database& query_explicit(const char* query_text, size_t text_length, const Params& params, Values&& values, ValueProc&& proc)
- {
- T* pThis=static_cast<T*>(this);
- Command command=pThis->open_command(query_text, text_length);
- command.execute(params);
- while(command.fetch(std::forward<Values>(values)))
+ template <typename Type, typename Ret>
+ inline Type make_values(Ret (Type::*)())
{
- if(!detail::apply(std::forward<ValueProc>(proc), std::forward<Values>(values))) break;
+ return Type();
+ };
+ template <typename Type, typename Ret>
+ inline Type make_values(Ret (Type::*)() const)
+ {
+ return Type();
+ };
+
+ template <typename Type, typename Ret, typename... Args>
+ inline auto make_values(Ret (Type::*)(Args...)) -> QTL_ARGS_TUPLE(Type, Args)
+ {
+ return QTL_ARGS_TUPLE(Type, Args)();
+ };
+ template <typename Type, typename Ret, typename... Args>
+ inline auto make_values(Ret (Type::*)(Args...) const) -> QTL_ARGS_TUPLE(Type, Args)
+ {
+ return QTL_ARGS_TUPLE(Type, Args)();
+ };
+
+ template <typename Type, typename Ret, typename Arg>
+ inline typename std::decay<Arg>::type make_values_noclass(Ret (Type::*)(Arg))
+ {
+ return typename std::decay<Arg>::type();
+ };
+ template <typename Type, typename Ret, typename Arg>
+ inline typename std::decay<Arg>::type make_values_noclass(Ret (Type::*)(Arg) const)
+ {
+ return typename std::decay<Arg>::type();
+ };
+
+ template <typename Type, typename Ret, typename Arg, typename... Others>
+ inline auto make_values_noclass(Ret (Type::*)(Arg, Others...)) -> QTL_ARGS_TUPLE(Arg, Others)
+ {
+ return QTL_ARGS_TUPLE(Arg, Others)();
+ };
+ template <typename Type, typename Ret, typename Arg, typename... Others>
+ inline auto make_values_noclass(Ret (Type::*)(Arg, Others...) const) -> QTL_ARGS_TUPLE(Arg, Others)
+ {
+ return QTL_ARGS_TUPLE(Arg, Others)();
+ };
+
+ template <typename Functor, typename = typename std::enable_if<std::is_member_function_pointer<decltype(&Functor::operator())>::value>::type>
+ inline auto make_values(const Functor &)
+ -> decltype(make_values_noclass(&Functor::operator()))
+ {
+ return make_values_noclass(&Functor::operator());
}
- command.close();
- return *this;
+
+ template <typename Command, typename ValueProc>
+ inline void fetch_command(Command &command, ValueProc &&proc)
+ {
+ auto values = make_values(proc);
+ typedef decltype(values) values_type;
+ while (command.fetch(std::forward<values_type>(values)))
+ {
+ if (!apply(std::forward<ValueProc>(proc), std::forward<values_type>(values)))
+ break;
+ }
+ }
+
+ template <typename Command, typename ValueProc, typename... OtherProc>
+ inline void fetch_command(Command &command, ValueProc &&proc, OtherProc &&...other)
+ {
+ fetch_command(command, std::forward<ValueProc>(proc));
+ if (command.next_result())
+ {
+ fetch_command(command, std::forward<OtherProc>(other)...);
+ }
+ }
+
}
- template<typename Params, typename Values, typename ValueProc>
- base_database& query_explicit(const char* query_text, const Params& params, Values&& values, ValueProc&& proc)
+ template <typename Command, typename T>
+ struct params_binder
{
- return query_explicit(query_text, strlen(query_text), params, std::forward<Values>(values), std::forward<ValueProc>(proc));
- }
- template<typename Params, typename Values, typename ValueProc>
- base_database& query_explicit(const std::string& query_text, const Params& params, Values&& values, ValueProc&& proc)
- {
- return query_explicit(query_text.data(), query_text.size(), params, std::forward<Values>(values), std::forward<ValueProc>(proc));
- }
- template<typename Values, typename ValueProc>
- base_database& query_explicit(const char* query_text, size_t text_length, Values&& values, ValueProc&& proc)
- {
- return query_explicit(query_text, text_length, std::make_tuple(), std::forward<Values>(values), std::forward<ValueProc>(proc));
- }
- template<typename Values, typename ValueProc>
- base_database& query_explicit(const char* query_text, Values&& values, ValueProc&& proc)
- {
- return query_explicit(query_text, strlen(query_text), std::make_tuple(), std::forward<Values>(values), std::forward<ValueProc>(proc));
- }
- template<typename Values, typename ValueProc>
- base_database& query_explicit(const std::string& query_text, Values&& values, ValueProc&& proc)
- {
- return query_explicit(query_text, std::make_tuple(), std::forward<Values>(values), std::forward<ValueProc>(proc));
- }
-
- template<typename Params, typename ValueProc>
- base_database& query(const char* query_text, size_t text_length, const Params& params, ValueProc&& proc)
- {
- return query_explicit(query_text, text_length, params, detail::make_values(proc), std::forward<ValueProc>(proc));
- }
- template<typename Params, typename ValueProc>
- base_database& query(const char* query_text, const Params& params, ValueProc&& proc)
- {
- return query_explicit(query_text, params, detail::make_values(proc), std::forward<ValueProc>(proc));
- }
- template<typename Params, typename ValueProc>
- base_database& query(const std::string& query_text, const Params& params, ValueProc&& proc)
- {
- return query_explicit(query_text, params, detail::make_values(proc), std::forward<ValueProc>(proc));
- }
- template<typename ValueProc>
- base_database& query(const char* query_text, size_t text_length, ValueProc&& proc)
- {
- return query_explicit(query_text, text_length, detail::make_values(proc), std::forward<ValueProc>(proc));
- }
- template<typename ValueProc>
- base_database& query(const char* query_text, ValueProc&& proc)
- {
- return query_explicit(query_text, detail::make_values(proc), std::forward<ValueProc>(proc));
- }
- template<typename ValueProc>
- base_database& query(const std::string& query_text, ValueProc&& proc)
- {
- return query_explicit(query_text, detail::make_values(proc), std::forward<ValueProc>(proc));
- }
-
- template<typename Params, typename... ValueProc>
- base_database& query_multi_with_params(const char* query_text, size_t text_length, const Params& params, ValueProc&&... proc)
- {
- T* pThis=static_cast<T*>(this);
- Command command=pThis->open_command(query_text, text_length);
- command.execute(params);
- detail::fetch_command(command, std::forward<ValueProc>(proc)...);
- command.close();
- return *this;
- }
- template<typename Params, typename... ValueProc>
- base_database& query_multi_with_params(const char* query_text, const Params& params, ValueProc&&... proc)
- {
- return query_multi_with_params(query_text, strlen(query_text), params, std::forward<ValueProc>(proc)...);
- }
- template<typename Params, typename... ValueProc>
- base_database& query_multi_with_params(const std::string& query_text, const Params& params, ValueProc&&... proc)
- {
- return query_multi_with_params(query_text.data(), query_text.size(), params, std::forward<ValueProc>(proc)...);
- }
- template<typename... ValueProc>
- base_database& query_multi(const char* query_text, size_t text_length, ValueProc&&... proc)
- {
- return query_multi_with_params<std::tuple<>, ValueProc...>(query_text, text_length, std::make_tuple(), std::forward<ValueProc>(proc)...);
- }
- template<typename... ValueProc>
- base_database& query_multi(const char* query_text, ValueProc&&... proc)
- {
- return query_multi_with_params<std::tuple<>, ValueProc...>(query_text, strlen(query_text), std::make_tuple(), std::forward<ValueProc>(proc)...);
- }
- template<typename... ValueProc>
- base_database& query_multi(const std::string& query_text, ValueProc&&... proc)
- {
- return query_multi_with_params<std::tuple<>, ValueProc...>(query_text.data(), query_text.size(), std::make_tuple(), std::forward<ValueProc>(proc)...);
- }
-
- template<typename Params, typename Values>
- bool query_first(const char* query_text, size_t text_length, const Params& params, Values&& values)
- {
- first_record fetcher;
- query_explicit(query_text, text_length, params, std::forward<Values>(values), std::ref(fetcher));
- return fetcher;
- }
-
- template<typename Params, typename Values>
- bool query_first(const char* query_text, const Params& params, Values&& values)
- {
- first_record fetcher;
- query_explicit(query_text, strlen(query_text), params, std::forward<Values>(values), std::ref(fetcher));
- return fetcher;
- }
-
- template<typename Params, typename Values>
- bool query_first(const std::string& query_text, const Params& params, Values&& values)
- {
- first_record fetcher;
- return query_explicit(query_text, params, values, std::ref(fetcher));
- return fetcher;
- }
-
- template<typename Values>
- bool query_first(const char* query_text, size_t text_length, Values&& values)
- {
- first_record fetcher;
- return query_explicit(query_text, text_length, std::make_tuple(), std::forward<Values>(values), std::ref(fetcher));
- return fetcher;
- }
-
- template<typename Values>
- bool query_first(const char* query_text, Values&& values)
- {
- first_record fetcher;
- query_explicit(query_text, strlen(query_text), std::make_tuple(), std::forward<Values>(values), std::ref(fetcher));
- return fetcher;
- }
-
- template<typename Values>
- bool query_first(const std::string& query_text, Values&& values)
- {
- first_record fetcher;
- return query_explicit(query_text, std::make_tuple(), std::forward<Values>(values), std::ref(fetcher));
- return fetcher;
- }
-
- template<typename... Values>
- bool query_first_direct(const char* query_text, size_t text_length, Values&... values)
- {
- return query_first(query_text, text_length, std::tie(values...));
- }
-
- template<typename... Values>
- bool query_first_direct(const char* query_text, Values&... values)
- {
- return query_first(query_text, std::tie(values...));
- }
-
- template<typename... Values>
- bool query_first_direct(const std::string& query_text, Values&... values)
- {
- return query_first(query_text, std::tie(values...));
- }
-
-protected:
- struct nothing
- {
- template<typename... Values> bool operator()(Values&&...) const { return true; }
+ enum
+ {
+ size = 1
+ };
+ inline void operator()(Command &command, const T ¶m) const
+ {
+ qtl::bind_param(command, 0, param);
+ }
};
- struct first_record
+
+ template <typename Command, typename... Types>
+ struct params_binder<Command, std::tuple<Types...>>
{
- first_record() : _found(false) { }
- template<typename... Values> bool operator()(Values&&...) { _found = true; return false; }
- operator bool() const { return _found; }
+ enum
+ {
+ size = sizeof...(Types)
+ };
+ void operator()(Command &command, const std::tuple<Types...> ¶ms) const
+ {
+ (detail::bind_helper<Command, std::tuple_size<std::tuple<Types...>>::value, Types...>(command))(params);
+ }
+ };
+
+ template <typename Command, typename Type1, typename Type2>
+ struct params_binder<Command, std::pair<Type1, Type2>>
+ {
+ enum
+ {
+ size = 2
+ };
+ void operator()(Command &command, std::pair<Type1, Type2> &&values) const
+ {
+ qtl::bind_param(command, 0, std::forward<Type1>(values.first));
+ qtl::bind_param(command, 1, std::forward<Type2>(values.second));
+ }
+ };
+
+ template <typename Command, typename T>
+ inline void bind_params(Command &command, const T ¶m)
+ {
+ params_binder<Command, T> binder;
+ binder(command, param);
+ }
+
+ template <typename Command, typename T>
+ struct record_binder
+ {
+ inline void operator()(Command &command, T &&value) const
+ {
+ bind_field(command, static_cast<size_t>(0), std::forward<typename std::remove_reference<T>::type>(value));
+ }
+ };
+
+ template <typename Command, typename T>
+ struct record_binder<Command, std::reference_wrapper<T>>
+ {
+ inline void operator()(Command &command, std::reference_wrapper<T> &&value) const
+ {
+ bind_field(command, static_cast<size_t>(0), std::forward<typename std::remove_reference<T>::type>(value.get()));
+ }
+ };
+
+ template <typename Command, typename... Types>
+ struct record_binder<Command, std::tuple<Types...>>
+ {
+ void operator()(Command &command, std::tuple<Types...> &&values) const
+ {
+ (detail::bind_helper<Command, std::tuple_size<std::tuple<Types...>>::value, Types...>(command))(std::forward<std::tuple<Types...>>(values));
+ }
+ };
+
+ template <typename Command, typename Type1, typename Type2>
+ struct record_binder<Command, std::pair<Type1, Type2>>
+ {
+ void operator()(Command &command, std::pair<Type1, Type2> &&values) const
+ {
+ bind_field(command, static_cast<size_t>(0), std::forward<Type1>(values.first));
+ bind_field(command, static_cast<size_t>(1), std::forward<Type2>(values.second));
+ }
+ };
+
+ template <typename T, typename Tag>
+ struct record_with_tag : public T
+ {
+ };
+
+ template <typename T, typename Pred>
+ struct custom_binder_type : public T
+ {
+ typedef T value_type;
+
+ explicit custom_binder_type(Pred pred) : m_pred(pred) {}
+ custom_binder_type(value_type &&v, Pred pred)
+ : value_type(std::forward<value_type>(v)), m_pred(pred)
+ {
+ }
+ template <typename... Args>
+ custom_binder_type(Pred pred, Args &&...args)
+ : value_type(std::forward<Args>(args)...), m_pred(pred)
+ {
+ }
+
+ template <typename Command>
+ void bind(Command &command)
+ {
+ m_pred(std::forward<T>(*this), command); // Pred maybe member function
+ }
private:
- bool _found;
+ Pred m_pred;
};
-};
-class blobbuf : public std::streambuf
-{
-public:
- blobbuf() = default;
- blobbuf(const blobbuf&) = default;
- blobbuf& operator=(const blobbuf&) = default;
- virtual ~blobbuf()
+ template <typename T, typename Pred>
+ struct custom_binder_type<std::reference_wrapper<T>, Pred> : public std::reference_wrapper<T>
{
- overflow();
- }
+ typedef std::reference_wrapper<T> value_type;
- void swap(blobbuf& other)
- {
- std::swap(m_buf, other.m_buf);
- std::swap(m_size, other.m_size);
- std::swap(m_pos, other.m_pos);
-
- std::streambuf::swap(other);
- }
-
-protected:
- virtual pos_type seekoff(off_type off, std::ios_base::seekdir dir,
- std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) override
- {
- if (which&std::ios_base::in)
+ explicit custom_binder_type(Pred pred) : m_pred(pred) {}
+ custom_binder_type(value_type &&v, Pred pred)
+ : value_type(std::forward<value_type>(v)), m_pred(pred)
{
- pos_type pos = 0;
- pos = seekoff(m_pos, off, dir);
- return seekpos(pos, which);
}
- return std::streambuf::seekoff(off, dir, which);
+ template <typename... Args>
+ custom_binder_type(Pred pred, Args &&...args)
+ : T(std::forward<Args>(args)...), m_pred(pred)
+ {
+ }
+
+ template <typename Command>
+ void bind(Command &command)
+ {
+ m_pred(std::forward<T>(*this), command); // Pred maybe member function
+ }
+
+ private:
+ Pred m_pred;
+ };
+
+ template <typename T, typename Pred>
+ inline custom_binder_type<T, Pred> custom_bind(T &&v, Pred pred)
+ {
+ return custom_binder_type<T, Pred>(std::forward<T>(v), pred);
}
- virtual pos_type seekpos(pos_type pos,
- std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) override
+ template <typename Command, typename T, typename Pred>
+ struct record_binder<Command, custom_binder_type<T, Pred>>
{
- if (pos >= m_size)
- return pos_type(off_type(-1));
-
- if (which&std::ios_base::out)
+ void operator()(Command &command, custom_binder_type<T, Pred> &&values) const
{
- if (pos < m_pos || pos >= m_pos + off_type(egptr() - pbase()))
+ values.bind(command);
+ }
+ };
+
+ template <typename Command, typename T>
+ inline void bind_record(Command &command, T &&value)
+ {
+ record_binder<Command, T> binder;
+ binder(command, std::forward<T>(value));
+ }
+
+ template <typename Command, typename Record>
+ class query_iterator final
+ {
+ public:
+ using iterator_category = std::forward_iterator_tag;
+ using value_type = Record;
+ using difference_type = ptrdiff_t;
+ using pointer = Record *;
+ using reference = Record &;
+
+ explicit query_iterator(Command &command)
+ : m_command(command) {}
+ Record *operator->() const { return m_record.get(); }
+ Record &operator*() const { return *m_record; }
+
+ query_iterator &operator++()
+ {
+ if (!m_record)
+ m_record = std::make_shared<Record>();
+ if (m_record.use_count() == 1)
{
- overflow();
- m_pos = pos;
- setp(m_buf.data(), m_buf.data() + m_buf.size());
+ if (!m_command.fetch(std::forward<Record>(*m_record)))
+ m_record.reset();
}
else
{
- pbump(off_type(pos - pabs()));
+ std::shared_ptr<Record> record = std::make_shared<Record>();
+ if (m_command.fetch(std::forward<Record>(*record)))
+ m_record = record;
+ else
+ m_record.reset();
+ }
+ return *this;
+ }
+ query_iterator operator++(int)
+ {
+ query_iterator temp = *this;
+ m_record = std::make_shared<Record>();
+ if (!m_command.fetch(std::forward<Record>(*m_record)))
+ m_record.reset();
+ return temp;
+ }
+
+ bool operator==(const query_iterator &rhs)
+ {
+ return &this->m_command == &rhs.m_command &&
+ this->m_record == rhs.m_record;
+ }
+ bool operator!=(const query_iterator &rhs)
+ {
+ return !(*this == rhs);
+ }
+
+ private:
+ Command &m_command;
+ std::shared_ptr<Record> m_record;
+ };
+
+ template <typename Command, typename Record>
+ class query_result final
+ {
+ public:
+ typedef typename query_iterator<Command, Record>::value_type value_type;
+ typedef typename query_iterator<Command, Record>::pointer pointer;
+ typedef typename query_iterator<Command, Record>::reference reference;
+ typedef query_iterator<Command, Record> iterator;
+
+ explicit query_result(Command &&command) : m_command(std::move(command)) {}
+ query_result(query_result &&src) : m_command(std::move(src.m_command)) {}
+ query_result &operator=(query_result &&src)
+ {
+ if (this != &src)
+ m_command = std::move(src.m_command);
+ return *this;
+ }
+
+ template <typename Params>
+ iterator begin(const Params ¶ms)
+ {
+ query_iterator<Command, Record> it(m_command);
+ ++it;
+ return it;
+ }
+ iterator begin()
+ {
+ return begin(std::make_tuple());
+ }
+
+ iterator end()
+ {
+ return query_iterator<Command, Record>(m_command);
+ }
+
+ private:
+ Command m_command;
+ };
+
+ template <typename T, class Command>
+ class base_database
+ {
+ public:
+ template <typename Params>
+ base_database &execute(const char *query_text, size_t text_length, const Params ¶ms, uint64_t *affected = NULL)
+ {
+ T *pThis = static_cast<T *>(this);
+ Command command = pThis->open_command(query_text, text_length);
+ command.execute(params);
+ if (affected)
+ *affected = command.affetced_rows();
+ command.close();
+ return *this;
+ }
+ template <typename Params>
+ base_database &execute(const char *query_text, const Params ¶ms, uint64_t *affected = NULL)
+ {
+ return execute(query_text, strlen(query_text), params, affected);
+ }
+ template <typename Params>
+ base_database &execute(const std::string &query_text, const Params ¶ms, uint64_t *affected = NULL)
+ {
+ return execute(query_text.data(), query_text.length(), params, affected);
+ }
+
+ template <typename... Params>
+ base_database &execute_direct(const char *query_text, size_t text_length, uint64_t *affected, const Params &...params)
+ {
+ return execute(query_text, text_length, std::forward_as_tuple(params...), affected);
+ }
+ template <typename... Params>
+ base_database &execute_direct(const char *query_text, uint64_t *affected, const Params &...params)
+ {
+ return execute(query_text, std::forward_as_tuple(params...), affected);
+ }
+ template <typename... Params>
+ base_database &execute_direct(const std::string &query_text, uint64_t *affected, const Params &...params)
+ {
+ return execute(query_text, std::forward_as_tuple(params...), affected);
+ }
+
+ template <typename Params>
+ uint64_t insert(const char *query_text, size_t text_length, const Params ¶ms)
+ {
+ uint64_t id = 0;
+ T *pThis = static_cast<T *>(this);
+ Command command = pThis->open_command(query_text, text_length);
+ command.execute(params);
+ if (command.affetced_rows() > 0)
+ id = command.insert_id();
+ return id;
+ }
+
+ template <typename Params>
+ uint64_t insert(const char *query_text, const Params ¶ms)
+ {
+ return insert(query_text, strlen(query_text), params);
+ }
+
+ template <typename Params>
+ uint64_t insert(const std::string &query_text, const Params ¶ms)
+ {
+ return insert(query_text.data(), query_text.length(), params);
+ }
+
+ template <typename... Params>
+ uint64_t insert_direct(const char *query_text, size_t text_length, const Params &...params)
+ {
+ return insert(query_text, text_length, std::forward_as_tuple(params...));
+ }
+
+ template <typename... Params>
+ uint64_t insert_direct(const char *query_text, const Params &...params)
+ {
+ return insert(query_text, strlen(query_text), std::forward_as_tuple(params...));
+ }
+
+ template <typename... Params>
+ uint64_t insert_direct(const std::string &query_text, const Params &...params)
+ {
+ return insert(query_text.data(), query_text.length(), std::forward_as_tuple(params...));
+ }
+
+ template <typename Record, typename Params>
+ query_result<Command, Record> result(const char *query_text, size_t text_length, const Params ¶ms)
+ {
+ T *pThis = static_cast<T *>(this);
+ Command command = pThis->open_command(query_text, text_length);
+ command.execute(params);
+ return query_result<Command, Record>(std::move(command));
+ }
+ template <typename Record, typename Params>
+ query_result<Command, Record> result(const char *query_text, const Params ¶ms)
+ {
+ return result<Record, Params>(query_text, strlen(query_text), params);
+ }
+ template <typename Record, typename Params>
+ query_result<Command, Record> result(const std::string &query_text, const Params ¶ms)
+ {
+ return result<Record, Params>(query_text.data(), query_text.length(), params);
+ }
+ template <typename Record>
+ query_result<Command, Record> result(const char *query_text, size_t text_length)
+ {
+ return result<Record>(query_text, text_length, std::make_tuple());
+ }
+ template <typename Record>
+ query_result<Command, Record> result(const char *query_text)
+ {
+ return result<Record>(query_text, strlen(query_text), std::make_tuple());
+ }
+ template <typename Record>
+ query_result<Command, Record> result(const std::string &query_text)
+ {
+ return result<Record>(query_text.data(), query_text.length(), std::make_tuple());
+ }
+
+ template <typename Params, typename Values, typename ValueProc>
+ base_database &query_explicit(const char *query_text, size_t text_length, const Params ¶ms, Values &&values, ValueProc &&proc)
+ {
+ T *pThis = static_cast<T *>(this);
+ Command command = pThis->open_command(query_text, text_length);
+ command.execute(params);
+ while (command.fetch(std::forward<Values>(values)))
+ {
+ if (!detail::apply(std::forward<ValueProc>(proc), std::forward<Values>(values)))
+ break;
+ }
+ command.close();
+ return *this;
+ }
+
+ template <typename Params, typename Values, typename ValueProc>
+ base_database &query_explicit(const char *query_text, const Params ¶ms, Values &&values, ValueProc &&proc)
+ {
+ return query_explicit(query_text, strlen(query_text), params, std::forward<Values>(values), std::forward<ValueProc>(proc));
+ }
+ template <typename Params, typename Values, typename ValueProc>
+ base_database &query_explicit(const std::string &query_text, const Params ¶ms, Values &&values, ValueProc &&proc)
+ {
+ return query_explicit(query_text.data(), query_text.size(), params, std::forward<Values>(values), std::forward<ValueProc>(proc));
+ }
+ template <typename Values, typename ValueProc>
+ base_database &query_explicit(const char *query_text, size_t text_length, Values &&values, ValueProc &&proc)
+ {
+ return query_explicit(query_text, text_length, std::make_tuple(), std::forward<Values>(values), std::forward<ValueProc>(proc));
+ }
+ template <typename Values, typename ValueProc>
+ base_database &query_explicit(const char *query_text, Values &&values, ValueProc &&proc)
+ {
+ return query_explicit(query_text, strlen(query_text), std::make_tuple(), std::forward<Values>(values), std::forward<ValueProc>(proc));
+ }
+ template <typename Values, typename ValueProc>
+ base_database &query_explicit(const std::string &query_text, Values &&values, ValueProc &&proc)
+ {
+ return query_explicit(query_text, std::make_tuple(), std::forward<Values>(values), std::forward<ValueProc>(proc));
+ }
+
+ template <typename Params, typename ValueProc>
+ base_database &query(const char *query_text, size_t text_length, const Params ¶ms, ValueProc &&proc)
+ {
+ return query_explicit(query_text, text_length, params, detail::make_values(proc), std::forward<ValueProc>(proc));
+ }
+ template <typename Params, typename ValueProc>
+ base_database &query(const char *query_text, const Params ¶ms, ValueProc &&proc)
+ {
+ return query_explicit(query_text, params, detail::make_values(proc), std::forward<ValueProc>(proc));
+ }
+ template <typename Params, typename ValueProc>
+ base_database &query(const std::string &query_text, const Params ¶ms, ValueProc &&proc)
+ {
+ return query_explicit(query_text, params, detail::make_values(proc), std::forward<ValueProc>(proc));
+ }
+ template <typename ValueProc>
+ base_database &query(const char *query_text, size_t text_length, ValueProc &&proc)
+ {
+ return query_explicit(query_text, text_length, detail::make_values(proc), std::forward<ValueProc>(proc));
+ }
+ template <typename ValueProc>
+ base_database &query(const char *query_text, ValueProc &&proc)
+ {
+ return query_explicit(query_text, detail::make_values(proc), std::forward<ValueProc>(proc));
+ }
+ template <typename ValueProc>
+ base_database &query(const std::string &query_text, ValueProc &&proc)
+ {
+ return query_explicit(query_text, detail::make_values(proc), std::forward<ValueProc>(proc));
+ }
+
+ template <typename Params, typename... ValueProc>
+ base_database &query_multi_with_params(const char *query_text, size_t text_length, const Params ¶ms, ValueProc &&...proc)
+ {
+ T *pThis = static_cast<T *>(this);
+ Command command = pThis->open_command(query_text, text_length);
+ command.execute(params);
+ detail::fetch_command(command, std::forward<ValueProc>(proc)...);
+ command.close();
+ return *this;
+ }
+ template <typename Params, typename... ValueProc>
+ base_database &query_multi_with_params(const char *query_text, const Params ¶ms, ValueProc &&...proc)
+ {
+ return query_multi_with_params(query_text, strlen(query_text), params, std::forward<ValueProc>(proc)...);
+ }
+ template <typename Params, typename... ValueProc>
+ base_database &query_multi_with_params(const std::string &query_text, const Params ¶ms, ValueProc &&...proc)
+ {
+ return query_multi_with_params(query_text.data(), query_text.size(), params, std::forward<ValueProc>(proc)...);
+ }
+ template <typename... ValueProc>
+ base_database &query_multi(const char *query_text, size_t text_length, ValueProc &&...proc)
+ {
+ return query_multi_with_params<std::tuple<>, ValueProc...>(query_text, text_length, std::make_tuple(), std::forward<ValueProc>(proc)...);
+ }
+ template <typename... ValueProc>
+ base_database &query_multi(const char *query_text, ValueProc &&...proc)
+ {
+ return query_multi_with_params<std::tuple<>, ValueProc...>(query_text, strlen(query_text), std::make_tuple(), std::forward<ValueProc>(proc)...);
+ }
+ template <typename... ValueProc>
+ base_database &query_multi(const std::string &query_text, ValueProc &&...proc)
+ {
+ return query_multi_with_params<std::tuple<>, ValueProc...>(query_text.data(), query_text.size(), std::make_tuple(), std::forward<ValueProc>(proc)...);
+ }
+
+ template <typename Params, typename Values>
+ bool query_first(const char *query_text, size_t text_length, const Params ¶ms, Values &&values)
+ {
+ first_record fetcher;
+ query_explicit(query_text, text_length, params, std::forward<Values>(values), std::ref(fetcher));
+ return fetcher;
+ }
+
+ template <typename Params, typename Values>
+ bool query_first(const char *query_text, const Params ¶ms, Values &&values)
+ {
+ first_record fetcher;
+ query_explicit(query_text, strlen(query_text), params, std::forward<Values>(values), std::ref(fetcher));
+ return fetcher;
+ }
+
+ template <typename Params, typename Values>
+ bool query_first(const std::string &query_text, const Params ¶ms, Values &&values)
+ {
+ first_record fetcher;
+ return query_explicit(query_text, params, values, std::ref(fetcher));
+ return fetcher;
+ }
+
+ template <typename Values>
+ bool query_first(const char *query_text, size_t text_length, Values &&values)
+ {
+ first_record fetcher;
+ return query_explicit(query_text, text_length, std::make_tuple(), std::forward<Values>(values), std::ref(fetcher));
+ return fetcher;
+ }
+
+ template <typename Values>
+ bool query_first(const char *query_text, Values &&values)
+ {
+ first_record fetcher;
+ query_explicit(query_text, strlen(query_text), std::make_tuple(), std::forward<Values>(values), std::ref(fetcher));
+ return fetcher;
+ }
+
+ template <typename Values>
+ bool query_first(const std::string &query_text, Values &&values)
+ {
+ first_record fetcher;
+ return query_explicit(query_text, std::make_tuple(), std::forward<Values>(values), std::ref(fetcher));
+ return fetcher;
+ }
+
+ template <typename... Values>
+ bool query_first_direct(const char *query_text, size_t text_length, Values &...values)
+ {
+ return query_first(query_text, text_length, std::tie(values...));
+ }
+
+ template <typename... Values>
+ bool query_first_direct(const char *query_text, Values &...values)
+ {
+ return query_first(query_text, std::tie(values...));
+ }
+
+ template <typename... Values>
+ bool query_first_direct(const std::string &query_text, Values &...values)
+ {
+ return query_first(query_text, std::tie(values...));
+ }
+
+ protected:
+ struct nothing
+ {
+ template <typename... Values>
+ bool operator()(Values &&...) const { return true; }
+ };
+ struct first_record
+ {
+ first_record() : _found(false) {}
+ template <typename... Values>
+ bool operator()(Values &&...)
+ {
+ _found = true;
+ return false;
+ }
+ operator bool() const { return _found; }
+
+ private:
+ bool _found;
+ };
+ };
+
+ class blobbuf : public std::streambuf
+ {
+ public:
+ blobbuf() = default;
+ blobbuf(const blobbuf &) = default;
+ blobbuf &operator=(const blobbuf &) = default;
+ virtual ~blobbuf()
+ {
+ overflow();
+ }
+
+ void swap(blobbuf &other)
+ {
+ std::swap(m_buf, other.m_buf);
+ std::swap(m_size, other.m_size);
+ std::swap(m_pos, other.m_pos);
+
+ std::streambuf::swap(other);
+ }
+
+ protected:
+ virtual pos_type seekoff(off_type off, std::ios_base::seekdir dir,
+ std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) override
+ {
+ if (which & std::ios_base::in)
+ {
+ pos_type pos = 0;
+ pos = seekoff(m_pos, off, dir);
+ return seekpos(pos, which);
+ }
+ return std::streambuf::seekoff(off, dir, which);
+ }
+
+ virtual pos_type seekpos(pos_type pos,
+ std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) override
+ {
+ if (pos >= m_size)
+ return pos_type(off_type(-1));
+
+ if (which & std::ios_base::out)
+ {
+ if (pos < m_pos || pos >= m_pos + off_type(egptr() - pbase()))
+ {
+ overflow();
+ m_pos = pos;
+ setp(m_buf.data(), m_buf.data() + m_buf.size());
+ }
+ else
+ {
+ pbump(off_type(pos - pabs()));
+ }
+ }
+ else if (which & std::ios_base::in)
+ {
+ if (pos < m_pos || pos >= m_pos + off_type(epptr() - eback()))
+ {
+ m_pos = pos;
+ setg(m_buf.data(), m_buf.data(), m_buf.data());
+ }
+ else
+ {
+ gbump(off_type(pos - gabs()));
+ }
+ }
+ return pos;
+ }
+
+ virtual std::streamsize showmanyc() override
+ {
+ return m_size - pabs();
+ }
+
+ virtual int_type underflow() override
+ {
+ if (pptr() > pbase())
+ overflow();
+
+ off_type count = egptr() - eback();
+ pos_type next_pos = 0;
+ if (count == 0 && eback() == m_buf.data())
+ {
+ setg(m_buf.data(), m_buf.data(), m_buf.data() + m_buf.size());
+ count = m_buf.size();
+ }
+ else
+ {
+ next_pos = m_pos + pos_type(count);
+ }
+ if (next_pos >= m_size)
+ return traits_type::eof();
+
+ count = std::min(count, m_size - next_pos);
+ m_pos = next_pos;
+ if (read_blob(m_buf.data(), count, m_pos))
+ {
+ setg(eback(), eback(), eback() + count);
+ return traits_type::to_int_type(*gptr());
+ }
+ else
+ {
+ return traits_type::eof();
}
}
- else if (which&std::ios_base::in)
+
+ virtual int_type overflow(int_type ch = traits_type::eof()) override
{
- if (pos < m_pos || pos >= m_pos + off_type(epptr() - eback()))
+ if (pptr() != pbase())
{
- m_pos = pos;
+ size_t count = pptr() - pbase();
+ write_blob(pbase(), count);
+
+ // auto intersection = interval_intersection(m_pos, egptr() - eback(), m_pos, epptr() - pbase());
+ // if (intersection.first != intersection.second)
+ //{
+ // commit(intersection.first, intersection.second);
+ // }
+
+ m_pos += count;
+ setp(pbase(), epptr());
+ }
+ if (!traits_type::eq_int_type(ch, traits_type::eof()))
+ {
+ char_type c = traits_type::to_char_type(ch);
+ if (m_pos >= m_size)
+ return traits_type::eof();
+ write_blob(&c, 1);
+
+ // auto intersection = interval_intersection(m_pos, egptr() - eback(), m_pos, 1);
+ // if (intersection.first != intersection.second)
+ //{
+ // eback()[intersection.first - m_pos] = c;
+ // }
+ m_pos += 1;
+ }
+ return ch;
+ }
+
+ virtual int_type pbackfail(int_type c = traits_type::eof()) override
+ {
+ if (gptr() == 0 || gptr() <= eback() || (!traits_type::eq_int_type(traits_type::eof(), c) && !traits_type::eq(traits_type::to_char_type(c), gptr()[-1])))
+ {
+ return (traits_type::eof()); // can't put back, fail
+ }
+ else
+ { // back up one position and store put-back character
+ gbump(-1);
+ if (!traits_type::eq_int_type(traits_type::eof(), c))
+ *gptr() = traits_type::to_char_type(c);
+ return (traits_type::not_eof(c));
+ }
+ }
+
+ private:
+ off_type seekoff(off_type position, off_type off, std::ios_base::seekdir dir)
+ {
+ off_type result = 0;
+ switch (dir)
+ {
+ case std::ios_base::beg:
+ result = off;
+ break;
+ case std::ios_base::cur:
+ result = position + off;
+ break;
+ case std::ios_base::end:
+ result = m_size - off;
+ }
+ if (result > m_size)
+ result = m_size;
+ return result;
+ }
+
+ pos_type gabs() const // absolute offset of input pointer in blob field
+ {
+ return m_pos + off_type(gptr() - eback());
+ }
+
+ pos_type pabs() const // absolute offset of output pointer in blob field
+ {
+ return m_pos + off_type(pptr() - pbase());
+ }
+
+ protected:
+ std::vector<char> m_buf;
+ pos_type m_size;
+ pos_type m_pos; // position in the input sequence
+
+ virtual bool read_blob(char *buffer, off_type &count, pos_type position) = 0;
+ virtual void write_blob(const char *buffer, size_t count) = 0;
+
+ void init_buffer(std::ios_base::openmode mode)
+ {
+ size_t bufsize;
+ if (m_size > 0)
+ bufsize = std::min<size_t>(blob_buffer_size, m_size);
+ else
+ bufsize = blob_buffer_size;
+ if (mode & std::ios_base::in)
+ {
+ m_buf.resize(bufsize);
+ m_pos = 0;
setg(m_buf.data(), m_buf.data(), m_buf.data());
}
- else
+ else if (mode & std::ios_base::out)
{
- gbump(off_type(pos - gabs()));
+ m_buf.resize(bufsize);
+ m_pos = 0;
+ setp(m_buf.data(), m_buf.data() + bufsize);
}
}
- return pos;
- }
+ };
- virtual std::streamsize showmanyc() override
+ typedef std::function<void(std::ostream &)> blob_writer;
+
+ template <typename Database>
+ struct transaction
{
- return m_size - pabs();
- }
+ transaction(Database &db) : m_db(db), m_commited(true)
+ {
+ begin();
+ }
+ ~transaction()
+ {
+ rollback();
+ }
+ void begin()
+ {
+ if (m_commited)
+ {
+ m_db.begin_transaction();
+ m_commited = false;
+ }
+ }
+ void rollback()
+ {
+ if (!m_commited)
+ {
+ m_db.rollback();
+ m_commited = true;
+ }
+ }
+ void commit()
+ {
+ if (!m_commited)
+ {
+ m_db.commit();
+ m_commited = true;
+ }
+ }
- virtual int_type underflow() override
+ private:
+ bool m_commited;
+ Database &m_db;
+ };
+
+ template <typename Command, typename Params, typename... Others>
+ inline void execute(Command &command, uint64_t *affected, const Params ¶ms)
{
- if (pptr() > pbase())
- overflow();
-
- off_type count = egptr() - eback();
- pos_type next_pos = 0;
- if (count == 0 && eback() == m_buf.data())
- {
- setg(m_buf.data(), m_buf.data(), m_buf.data() + m_buf.size());
- count = m_buf.size();
- }
- else
- {
- next_pos = m_pos + pos_type(count);
- }
- if (next_pos >= m_size)
- return traits_type::eof();
-
- count = std::min(count, m_size - next_pos);
- m_pos = next_pos;
- if (read_blob(m_buf.data(), count, m_pos))
- {
- setg(eback(), eback(), eback() + count);
- return traits_type::to_int_type(*gptr());
- }
- else
- {
- return traits_type::eof();
- }
+ command.reset();
+ command.execute(params);
+ if (affected)
+ *affected += command.affetced_rows();
}
- virtual int_type overflow(int_type ch = traits_type::eof()) override
+ template <typename Command, typename Params, typename... Others>
+ inline void execute(Command &command, uint64_t *affected, const Params ¶ms, const Others &...others)
{
- if (pptr() != pbase())
- {
- size_t count = pptr() - pbase();
- write_blob(pbase(), count);
-
- //auto intersection = interval_intersection(m_pos, egptr() - eback(), m_pos, epptr() - pbase());
- //if (intersection.first != intersection.second)
- //{
- // commit(intersection.first, intersection.second);
- //}
-
- m_pos += count;
- setp(pbase(), epptr());
- }
- if (!traits_type::eq_int_type(ch, traits_type::eof()))
- {
- char_type c = traits_type::to_char_type(ch);
- if (m_pos >= m_size)
- return traits_type::eof();
- write_blob(&c, 1);
-
- //auto intersection = interval_intersection(m_pos, egptr() - eback(), m_pos, 1);
- //if (intersection.first != intersection.second)
- //{
- // eback()[intersection.first - m_pos] = c;
- //}
- m_pos += 1;
-
- }
- return ch;
+ execute(command, affected, params);
+ execute(command, affected, others...);
}
-
- virtual int_type pbackfail(int_type c = traits_type::eof()) override
- {
- if (gptr() == 0
- || gptr() <= eback()
- || (!traits_type::eq_int_type(traits_type::eof(), c)
- && !traits_type::eq(traits_type::to_char_type(c), gptr()[-1])))
- {
- return (traits_type::eof()); // can't put back, fail
- }
- else
- { // back up one position and store put-back character
- gbump(-1);
- if (!traits_type::eq_int_type(traits_type::eof(), c))
- *gptr() = traits_type::to_char_type(c);
- return (traits_type::not_eof(c));
- }
- }
-
-private:
-
- off_type seekoff(off_type position, off_type off, std::ios_base::seekdir dir)
- {
- off_type result = 0;
- switch (dir)
- {
- case std::ios_base::beg:
- result = off;
- break;
- case std::ios_base::cur:
- result = position + off;
- break;
- case std::ios_base::end:
- result = m_size - off;
- }
- if (result > m_size)
- result = m_size;
- return result;
- }
-
- pos_type gabs() const // absolute offset of input pointer in blob field
- {
- return m_pos + off_type(gptr() - eback());
- }
-
- pos_type pabs() const // absolute offset of output pointer in blob field
- {
- return m_pos + off_type(pptr() - pbase());
- }
-
-protected:
- std::vector<char> m_buf;
- pos_type m_size;
- pos_type m_pos; //position in the input sequence
-
- virtual bool read_blob(char* buffer, off_type& count, pos_type position) = 0;
- virtual void write_blob(const char* buffer, size_t count) = 0;
-
- void init_buffer(std::ios_base::openmode mode)
- {
- size_t bufsize;
- if (m_size > 0)
- bufsize = std::min<size_t>(blob_buffer_size, m_size);
- else
- bufsize = blob_buffer_size;
- if (mode&std::ios_base::in)
- {
- m_buf.resize(bufsize);
- m_pos = 0;
- setg(m_buf.data(), m_buf.data(), m_buf.data());
- }
- else if (mode&std::ios_base::out)
- {
- m_buf.resize(bufsize);
- m_pos = 0;
- setp(m_buf.data(), m_buf.data() + bufsize);
- }
- }
-};
-
-typedef std::function<void(std::ostream&)> blob_writer;
-
-template<typename Database>
-struct transaction
-{
- transaction(Database& db) : m_db(db), m_commited(true)
- {
- begin();
- }
- ~transaction()
- {
- rollback();
- }
- void begin()
- {
- if(m_commited)
- {
- m_db.begin_transaction();
- m_commited=false;
- }
- }
- void rollback()
- {
- if(!m_commited)
- {
- m_db.rollback();
- m_commited=true;
- }
- }
- void commit()
- {
- if(!m_commited)
- {
- m_db.commit();
- m_commited=true;
- }
- }
-private:
- bool m_commited;
- Database& m_db;
-};
-
-template<typename Command, typename Params, typename... Others>
-inline void execute(Command& command, uint64_t* affected, const Params& params)
-{
- command.reset();
- command.execute(params);
- if(affected) *affected+=command.affetced_rows();
-}
-
-template<typename Command, typename Params, typename... Others>
-inline void execute(Command& command, uint64_t* affected, const Params& params, const Others&... others)
-{
- execute(command, affected, params);
- execute(command, affected, others...);
-}
}
diff --git a/include/qtl_database_pool.hpp b/include/qtl_database_pool.hpp
index 4b53dfd..c7d17d9 100644
--- a/include/qtl_database_pool.hpp
+++ b/include/qtl_database_pool.hpp
@@ -12,224 +12,228 @@
namespace qtl
{
-template<typename Database>
-class database_pool
-{
-public:
- typedef Database value_type;
- typedef std::shared_ptr<Database> pointer;
-
- database_pool()
- : m_trying_connection(false), m_stop_thread(false)
+ template <typename Database>
+ class database_pool
{
- }
+ public:
+ typedef Database value_type;
+ typedef std::shared_ptr<Database> pointer;
- virtual ~database_pool()
- {
- if(m_background_thread.joinable())
+ database_pool()
+ : m_trying_connection(false), m_stop_thread(false)
{
- m_stop_thread=true;
- try
- {
- m_background_thread.join();
- }
- catch (std::system_error&)
- {
- //igore the error
- }
}
- clear();
- }
- pointer get()
- {
- Database* db=popup();
- if(db==NULL && m_trying_connection==false)
- db=create_database();
- return pointer(db, [this](Database* db) {
- recovery(db);
- });
- }
-
- bool test_alive()
- {
- if(m_databases.empty())
- return false;
- std::unique_lock<std::mutex> lock(m_pool_mutex);
- auto it=m_databases.begin();
- while(it!=m_databases.end())
+ virtual ~database_pool()
{
- Database* db=*it;
- if(!db->is_alive())
+ if (m_background_thread.joinable())
{
- delete db;
- it=m_databases.erase(it);
+ m_stop_thread = true;
+ try
+ {
+ m_background_thread.join();
+ }
+ catch (std::system_error &)
+ {
+ // igore the error
+ }
+ }
+ clear();
+ }
+
+ pointer get()
+ {
+ Database *db = popup();
+ if (db == NULL && m_trying_connection == false)
+ db = create_database();
+ return pointer(db, [this](Database *db)
+ { recovery(db); });
+ }
+
+ bool test_alive()
+ {
+ if (m_databases.empty())
+ return false;
+ std::unique_lock<std::mutex> lock(m_pool_mutex);
+ auto it = m_databases.begin();
+ while (it != m_databases.end())
+ {
+ Database *db = *it;
+ if (!db->is_alive())
+ {
+ delete db;
+ it = m_databases.erase(it);
+ }
+ else
+ {
+ ++it;
+ }
+ }
+ if (m_databases.empty())
+ {
+ lock.unlock();
+ try_connect();
+ return false;
+ }
+ else
+ return true;
+ }
+
+ private:
+ std::vector<Database *> m_databases;
+ std::mutex m_pool_mutex;
+ std::atomic<bool> m_trying_connection;
+ std::thread m_background_thread;
+ bool m_stop_thread;
+
+ virtual Database *new_database() throw() = 0;
+ void recovery(Database *db)
+ {
+ if (db == NULL)
+ return;
+ if (db->is_alive())
+ {
+ std::lock_guard<std::mutex> lock(m_pool_mutex);
+ m_databases.push_back(db);
}
else
{
- ++it;
+ delete db;
+ {
+ std::lock_guard<std::mutex> lock(m_pool_mutex);
+ clear();
+ }
+ try_connect();
}
}
- if(m_databases.empty())
- {
- lock.unlock();
- try_connect();
- return false;
- }
- else return true;
- }
-private:
- std::vector<Database*> m_databases;
- std::mutex m_pool_mutex;
- std::atomic<bool> m_trying_connection;
- std::thread m_background_thread;
- bool m_stop_thread;
+ Database *create_database()
+ {
+ Database *db = new_database();
+ if (db)
+ return db;
- virtual Database* new_database() throw()=0;
- void recovery(Database* db)
- {
- if(db==NULL) return;
- if(db->is_alive())
- {
- std::lock_guard<std::mutex> lock(m_pool_mutex);
- m_databases.push_back(db);
- }
- else
- {
- delete db;
{
std::lock_guard<std::mutex> lock(m_pool_mutex);
clear();
}
try_connect();
+ return NULL;
}
- }
- Database* create_database()
- {
- Database* db=new_database();
- if(db) return db;
-
+ Database *popup()
{
+ Database *db = NULL;
std::lock_guard<std::mutex> lock(m_pool_mutex);
- clear();
- }
- try_connect();
- return NULL;
- }
-
- Database* popup()
- {
- Database* db=NULL;
- std::lock_guard<std::mutex> lock(m_pool_mutex);
- if(!m_databases.empty())
- {
- db=m_databases.back();
- m_databases.pop_back();
- }
- return db;
- }
-
- void try_connect()
- {
- if(m_trying_connection)
- return;
-
- m_trying_connection=true;
-
- try
- {
- m_background_thread=std::thread(&database_pool<Database>::background_connect, this);
- }
- catch (std::system_error&)
- {
- m_trying_connection=false;
- }
- }
-
- void background_connect()
- {
- Database* db=NULL;
- int interval=1;
- while(db==NULL && m_stop_thread==false)
- {
- db=create_database();
- if(db==NULL)
+ if (!m_databases.empty())
{
- std::this_thread::sleep_for(std::chrono::seconds(interval));
- if(interval<60) interval<<=1;
+ db = m_databases.back();
+ m_databases.pop_back();
+ }
+ return db;
+ }
+
+ void try_connect()
+ {
+ if (m_trying_connection)
+ return;
+
+ m_trying_connection = true;
+
+ try
+ {
+ m_background_thread = std::thread(&database_pool<Database>::background_connect, this);
+ }
+ catch (std::system_error &)
+ {
+ m_trying_connection = false;
}
}
- if(db)
+
+ void background_connect()
{
- recovery(db);
+ Database *db = NULL;
+ int interval = 1;
+ while (db == NULL && m_stop_thread == false)
+ {
+ db = create_database();
+ if (db == NULL)
+ {
+ std::this_thread::sleep_for(std::chrono::seconds(interval));
+ if (interval < 60)
+ interval <<= 1;
+ }
+ }
+ if (db)
+ {
+ recovery(db);
+ }
+ m_background_thread.detach();
+ m_trying_connection = false;
}
- m_background_thread.detach();
- m_trying_connection=false;
- }
- void clear()
- {
- std::for_each(m_databases.begin(), m_databases.end(), std::default_delete<Database>());
- m_databases.clear();
- }
-};
-
-template<typename T, typename EventLoop, typename Connection>
-class async_pool
-{
-public:
- typedef Connection value_type;
- typedef std::shared_ptr<Connection> pointer;
-
- async_pool(EventLoop& ev)
- : m_ev(ev), m_trying_connecting(false)
- {
- }
-
- virtual ~async_pool()
- {
- clear();
- }
-
- /*
- Handler defines as:
- void handler(const pointer& ptr);
- */
- template<typename Handler>
- void get(Handler&& handler, EventLoop* ev=nullptr)
- {
- Connection* db = popup();
- if(ev==nullptr) ev=&m_ev;
-
- if(db)
+ void clear()
{
- db->bind(*ev);
- handler(typename Connection::exception_type(), wrap(db));
+ std::for_each(m_databases.begin(), m_databases.end(), std::default_delete<Database>());
+ m_databases.clear();
}
- else if (m_trying_connecting == false)
- {
- create_connection(ev, [this, handler](const typename Connection::exception_type& e, Connection* db) {
- handler(e, wrap(db));
- });
- }
- else
- {
- handler(typename Connection::exception_type(), nullptr);
- }
- }
+ };
- void test_alive()
+ template <typename T, typename EventLoop, typename Connection>
+ class async_pool
{
- if (m_connections.empty())
- return;
- std::unique_lock<std::mutex> lock(m_pool_mutex);
- auto it = m_connections.begin();
- while (it != m_connections.end())
+ public:
+ typedef Connection value_type;
+ typedef std::shared_ptr<Connection> pointer;
+
+ async_pool(EventLoop &ev)
+ : m_ev(ev), m_trying_connecting(false)
{
- Connection* db = *it;
- db->is_alive([this, db](const typename Connection::exception_type& e) {
+ }
+
+ virtual ~async_pool()
+ {
+ clear();
+ }
+
+ /*
+ Handler defines as:
+ void handler(const pointer& ptr);
+ */
+ template <typename Handler>
+ void get(Handler &&handler, EventLoop *ev = nullptr)
+ {
+ Connection *db = popup();
+ if (ev == nullptr)
+ ev = &m_ev;
+
+ if (db)
+ {
+ db->bind(*ev);
+ handler(typename Connection::exception_type(), wrap(db));
+ }
+ else if (m_trying_connecting == false)
+ {
+ create_connection(ev, [this, handler](const typename Connection::exception_type &e, Connection *db)
+ { handler(e, wrap(db)); });
+ }
+ else
+ {
+ handler(typename Connection::exception_type(), nullptr);
+ }
+ }
+
+ void test_alive()
+ {
+ if (m_connections.empty())
+ return;
+ std::unique_lock<std::mutex> lock(m_pool_mutex);
+ auto it = m_connections.begin();
+ while (it != m_connections.end())
+ {
+ Connection *db = *it;
+ db->is_alive([this, db](const typename Connection::exception_type &e)
+ {
if (e)
{
std::unique_lock<std::mutex> lock(m_pool_mutex);
@@ -238,22 +242,23 @@
m_connections.erase(it);
if (m_connections.empty())
try_connect();
- }
- });
- ++it;
+ } });
+ ++it;
+ }
}
- }
-private:
- EventLoop& m_ev;
- std::vector<Connection*> m_connections;
- std::recursive_mutex m_pool_mutex;
- std::atomic<bool> m_trying_connecting;
+ private:
+ EventLoop &m_ev;
+ std::vector<Connection *> m_connections;
+ std::recursive_mutex m_pool_mutex;
+ std::atomic<bool> m_trying_connecting;
- void recovery(Connection* db)
- {
- if (db == NULL) return;
- db->is_alive([this, db](const typename Connection::exception_type& e) {
+ void recovery(Connection *db)
+ {
+ if (db == NULL)
+ return;
+ db->is_alive([this, db](const typename Connection::exception_type &e)
+ {
if (e)
{
{
@@ -268,15 +273,15 @@
throw std::runtime_error("destroy a busysing connection.");
std::lock_guard<std::recursive_mutex> lock(m_pool_mutex);
m_connections.push_back(db);
- }
- });
- }
+ } });
+ }
- template<typename Handler>
- void create_connection(EventLoop* ev, Handler&& handler)
- {
- T* pThis = static_cast<T*>(this);
- pThis->new_connection(*ev, [this, handler](const typename Connection::exception_type& e, Connection* db) {
+ template <typename Handler>
+ void create_connection(EventLoop *ev, Handler &&handler)
+ {
+ T *pThis = static_cast<T *>(this);
+ pThis->new_connection(*ev, [this, handler](const typename Connection::exception_type &e, Connection *db)
+ {
handler(e, db);
if (!db)
{
@@ -287,29 +292,29 @@
m_ev.set_timeout(tv, [this]() {
try_connect();
});
- }
- });
- }
-
- Connection* popup()
- {
- Connection* db = nullptr;
- std::lock_guard<std::recursive_mutex> lock(m_pool_mutex);
- if (!m_connections.empty())
- {
- db = m_connections.back();
- m_connections.pop_back();
+ } });
}
- return db;
- }
- void try_connect()
- {
- if (m_trying_connecting)
- return;
+ Connection *popup()
+ {
+ Connection *db = nullptr;
+ std::lock_guard<std::recursive_mutex> lock(m_pool_mutex);
+ if (!m_connections.empty())
+ {
+ db = m_connections.back();
+ m_connections.pop_back();
+ }
+ return db;
+ }
- m_trying_connecting = true;
- create_connection(&m_ev, [this](const typename Connection::exception_type& e, Connection* db) {
+ void try_connect()
+ {
+ if (m_trying_connecting)
+ return;
+
+ m_trying_connecting = true;
+ create_connection(&m_ev, [this](const typename Connection::exception_type &e, Connection *db)
+ {
if (db)
{
std::lock_guard<std::recursive_mutex> lock(m_pool_mutex);
@@ -318,27 +323,26 @@
else
{
m_trying_connecting = false;
- }
- });
- }
-
- void clear()
- {
- std::for_each(m_connections.begin(), m_connections.end(), std::default_delete<Connection>());
- m_connections.clear();
- }
-
- pointer wrap(Connection* db)
- {
- if (db)
- {
- return pointer(db, [this](Connection* db) {
- recovery(db);
- });
+ } });
}
- else return nullptr;
- }
-};
+
+ void clear()
+ {
+ std::for_each(m_connections.begin(), m_connections.end(), std::default_delete<Connection>());
+ m_connections.clear();
+ }
+
+ pointer wrap(Connection *db)
+ {
+ if (db)
+ {
+ return pointer(db, [this](Connection *db)
+ { recovery(db); });
+ }
+ else
+ return nullptr;
+ }
+ };
}
diff --git a/include/qtl_mysql.hpp b/include/qtl_mysql.hpp
index 2b39807..c07ec69 100644
--- a/include/qtl_mysql.hpp
+++ b/include/qtl_mysql.hpp
@@ -18,1722 +18,1760 @@
#include "qtl_common.hpp"
#include "qtl_async.hpp"
-#if LIBMYSQL_VERSION_ID >=80000
+#if LIBMYSQL_VERSION_ID >= 80000
typedef bool my_bool;
-#endif //MySQL 8
+#endif // MySQL 8
#ifdef MARIADB_VERSION_ID
#define IS_LONGDATA(t) ((t) >= MYSQL_TYPE_TINY_BLOB && (t) <= MYSQL_TYPE_STRING)
-#endif //MariaDB
+#endif // MariaDB
namespace qtl
{
-namespace mysql
-{
+ namespace mysql
+ {
-struct init
-{
- init(int argc=-1, char **argv=nullptr, char **groups=nullptr)
- {
- //my_init();
- mysql_library_init(argc, argv, groups);
- }
- ~init()
- {
- mysql_library_end();
- }
-};
-
-struct thread_init
-{
- thread_init()
- {
- mysql_thread_init();
- }
- ~thread_init()
- {
- mysql_thread_end();
- }
-};
-
-class binder : public MYSQL_BIND
-{
- friend class statement;
-public:
- binder()
- {
- init();
- }
- void init()
- {
- memset(this, 0, sizeof(MYSQL_BIND));
- }
- void bind()
- {
- init();
- buffer_type=MYSQL_TYPE_NULL;
- }
- void bind(null)
- {
- bind();
- }
- void bind(std::nullptr_t)
- {
- bind();
- }
- void bind(bool& v)
- {
- init();
- buffer_type = MYSQL_TYPE_BIT;
- buffer = &v;
- buffer_length = 1;
- }
- void bind(int8_t& v)
- {
- init();
- buffer_type=MYSQL_TYPE_TINY;
- buffer=&v;
- }
- void bind(uint8_t& v)
- {
- init();
- buffer_type=MYSQL_TYPE_TINY;
- buffer=&v;
- is_unsigned=true;
- }
- void bind(int16_t& v)
- {
- init();
- buffer_type=MYSQL_TYPE_SHORT;
- buffer=&v;
- }
- void bind(uint16_t& v)
- {
- init();
- buffer_type=MYSQL_TYPE_SHORT;
- buffer=&v;
- is_unsigned=true;
- }
- void bind(int32_t& v)
- {
- init();
- buffer_type=MYSQL_TYPE_LONG;
- buffer=&v;
- }
- void bind(uint32_t& v)
- {
- init();
- buffer_type=MYSQL_TYPE_LONG;
- buffer=&v;
- is_unsigned=true;
- }
- void bind(int64_t& v)
- {
- init();
- buffer_type=MYSQL_TYPE_LONGLONG;
- buffer=&v;
- }
- void bind(uint64_t& v)
- {
- init();
- buffer_type=MYSQL_TYPE_LONGLONG;
- buffer=&v;
- is_unsigned=true;
- }
- void bind(double& v)
- {
- init();
- buffer_type=MYSQL_TYPE_DOUBLE;
- buffer=&v;
- }
- void bind(float& v)
- {
- init();
- buffer_type=MYSQL_TYPE_FLOAT;
- buffer=&v;
- }
- void bind(MYSQL_TIME& v, enum_field_types type=MYSQL_TYPE_TIMESTAMP)
- {
- init();
- buffer_type=type;
- buffer=&v;
- }
- void bind(void* data, unsigned long length, enum_field_types type=MYSQL_TYPE_BLOB)
- {
- init();
- buffer_type=type;
- buffer=data;
- buffer_length=length;
- }
- void bind(const const_blob_data& data, enum_field_types type=MYSQL_TYPE_BLOB)
- {
- init();
- buffer_type=type;
- buffer=const_cast<void*>(data.data);
- buffer_length=data.size;
- }
- void bind(blob_data& data, enum_field_types type=MYSQL_TYPE_BLOB)
- {
- init();
- buffer_type=type;
- buffer=data.data;
- buffer_length=data.size;
- }
-};
-
-
-template<typename T>
-inline void bind(binder& binder, const T& v)
-{
- binder.bind(const_cast<T&>(v));
-}
-
-template<typename T>
-inline void bind(binder& binder, T&& v)
-{
- binder.bind(v);
-}
-
-inline void bind(binder& binder, const char* str, size_t length=0)
-{
- if(length==0) length=strlen(str);
- binder.bind(const_cast<char*>(str), static_cast<unsigned long>(length), MYSQL_TYPE_VAR_STRING);
-}
-
-class base_statement;
-class basic_database;
-
-class error : public std::exception
-{
-public:
- error() : m_error(0) { }
- error(unsigned int err, const char* errmsg) : m_error(err), m_errmsg(errmsg) { }
- explicit error(const base_statement& stmt);
- explicit error(const basic_database& db);
- error(const error& src) = default;
- virtual ~error() throw() { }
- int code() const throw() { return m_error; }
- operator bool() const { return m_error != 0; }
- virtual const char* what() const NOEXCEPT override { return m_errmsg.data(); }
-private:
- unsigned int m_error;
- std::string m_errmsg;
-};
-
-class blobbuf : public qtl::blobbuf
-{
-public:
- blobbuf() : m_stmt(nullptr), m_field(0)
- {
- }
- blobbuf(const blobbuf&) = default;
- blobbuf& operator=(const blobbuf&) = default;
- virtual ~blobbuf() { overflow(); }
-
- void open(MYSQL_STMT* stmt, int field, const binder& b, std::ios_base::openmode mode)
- {
- if (m_stmt && m_field)
+ struct init
{
- overflow();
- }
-
- assert(stmt != nullptr);
- m_stmt = stmt;
- m_field = field;
- m_binder = b;
- if (b.length) m_size = *b.length;
- init_buffer(mode);
- }
-
- void swap(blobbuf& other)
- {
- std::swap(m_stmt, other.m_stmt);
- std::swap(m_binder, other.m_binder);
- std::swap(m_field, other.m_field);
- qtl::blobbuf::swap(other);
- }
-
-private:
- MYSQL_STMT* m_stmt;
- binder m_binder;
- int m_field;
-
-protected:
- virtual bool read_blob(char* buffer, off_type& count, pos_type position) override
- {
- m_binder.buffer = buffer;
- m_binder.buffer_length = count;
- int ret = mysql_stmt_fetch_column(m_stmt, &m_binder, m_field, position);
- switch (ret)
- {
- case 0:
- count = std::min(m_binder.buffer_length, *m_binder.length);
- return true;
- case CR_NO_DATA:
- return false;
- default:
- throw error(mysql_stmt_errno(m_stmt), mysql_stmt_error(m_stmt));
- }
- }
-
- virtual void write_blob(const char* buffer, size_t count) override
- {
- int ret = mysql_stmt_send_long_data(m_stmt, m_field, buffer, count);
- if (ret != 0)
- throw error(mysql_stmt_errno(m_stmt), mysql_stmt_error(m_stmt));
- }
-};
-
-struct time : public MYSQL_TIME
-{
- time()
- {
- memset(this, 0, sizeof(MYSQL_TIME));
- time_type = MYSQL_TIMESTAMP_NONE;
- }
- time(const struct tm& tm)
- {
- memset(this, 0, sizeof(MYSQL_TIME));
- year = tm.tm_year + 1900;
- month = tm.tm_mon + 1;
- day = tm.tm_mday;
- hour = tm.tm_hour;
- minute = tm.tm_min;
- second = tm.tm_sec;
- time_type = MYSQL_TIMESTAMP_DATETIME;
- }
- time(time_t value)
- {
- struct tm tm;
-#if defined(_MSC_VER)
- localtime_s(&tm, &value);
-#elif defined(_POSIX_VERSION)
- localtime_r(&value, &tm);
-#else
- tm = *localtime(&value);
-#endif
- new(this)time(tm);
- }
- time(const time& src)
- {
- memcpy(this, &src, sizeof(MYSQL_TIME));
- }
- time& operator=(const time& src)
- {
- if (this != &src)
- memcpy(this, &src, sizeof(MYSQL_TIME));
- return *this;
- }
-
- static time now()
- {
- time_t value;
- ::time(&value);
- return time(value);
- }
-
- time_t as_tm(struct tm& tm) const
- {
- tm.tm_year = year - 1900;
- tm.tm_mon = month - 1;
- tm.tm_mday = day;
- tm.tm_hour = hour;
- tm.tm_min = minute;
- tm.tm_sec = second;
- return mktime(&tm);
- }
- time_t get_time() const
- {
- struct tm tm;
- return as_tm(tm);
- }
-};
-
-class base_statement
-{
-protected:
- base_statement() : m_stmt(nullptr), m_result(nullptr) {}
- base_statement(const base_statement&) = delete;
- explicit base_statement(basic_database& db);
- base_statement(base_statement&& src)
- : m_stmt(src.m_stmt), m_result(src.m_result),
- m_binders(std::move(src.m_binders)), m_binderAddins(std::move(src.m_binderAddins))
- {
- src.m_stmt=nullptr;
- src.m_result=nullptr;
- }
- base_statement& operator=(const base_statement&) = delete;
- base_statement& operator=(base_statement&& src)
- {
- if(this!=&src)
- {
- m_stmt=src.m_stmt;
- m_result=src.m_result;
- src.m_stmt=nullptr;
- src.m_result=nullptr;
- m_binders=std::move(src.m_binders);
- m_binderAddins=std::move(src.m_binderAddins);
- }
- return *this;
- }
-
-public:
- operator MYSQL_STMT*() { return m_stmt; }
-
- unsigned int get_parameter_count() const { return mysql_stmt_param_count(m_stmt); }
- unsigned int get_column_count() const { return mysql_stmt_field_count(m_stmt); }
-
- unsigned long length(unsigned int index) const
- {
- return m_binderAddins[index].m_length;
- }
-
- bool is_null(unsigned int index) const
- {
- return m_binderAddins[index].m_isNull!=0;
- }
-
- size_t find_field(const char* name) const
- {
- if(m_result)
- {
- for(size_t i=0; i!=m_result->field_count; i++)
+ init(int argc = -1, char **argv = nullptr, char **groups = nullptr)
{
- if(strncmp(m_result->fields[i].name, name, m_result->fields[i].name_length)==0)
- return i;
+ // my_init();
+ mysql_library_init(argc, argv, groups);
}
- }
- return -1;
- }
-
- my_ulonglong affetced_rows()
- {
- return mysql_stmt_affected_rows(m_stmt);
- }
- my_ulonglong insert_id()
- {
- return mysql_stmt_insert_id(m_stmt);
- }
-
- binder* get_binder(unsigned long index)
- {
- return &m_binders[index];
- }
-
- unsigned int error() const
- {
- return mysql_stmt_errno(m_stmt);
- }
- const char* errmsg() const
- {
- return mysql_stmt_error(m_stmt);
- }
-
- MYSQL_RES* result() { return m_result; }
-
- void bind_param(size_t index, const char* param, size_t length)
- {
- bind(m_binders[index], param, length);
- }
-
- void bind_param(size_t index, const std::nullptr_t&)
- {
- m_binders[index].bind();
- }
-
- void bind_param(size_t index, std::istream& param)
- {
- m_binders[index].bind(nullptr, 0, MYSQL_TYPE_LONG_BLOB);
- m_binderAddins[index].m_after_fetch = [this, index, ¶m](const binder&) {
- std::array<char, blob_buffer_size> buffer;
- unsigned long readed = 0;
- while (!param.eof() && !param.fail())
+ ~init()
{
- param.read(buffer.data(), buffer.size());
- readed = (unsigned long)param.gcount();
- if (readed > 0)
+ mysql_library_end();
+ }
+ };
+
+ struct thread_init
+ {
+ thread_init()
+ {
+ mysql_thread_init();
+ }
+ ~thread_init()
+ {
+ mysql_thread_end();
+ }
+ };
+
+ class binder : public MYSQL_BIND
+ {
+ friend class statement;
+
+ public:
+ binder()
+ {
+ init();
+ }
+ void init()
+ {
+ memset(this, 0, sizeof(MYSQL_BIND));
+ }
+ void bind()
+ {
+ init();
+ buffer_type = MYSQL_TYPE_NULL;
+ }
+ void bind(null)
+ {
+ bind();
+ }
+ void bind(std::nullptr_t)
+ {
+ bind();
+ }
+ void bind(bool &v)
+ {
+ init();
+ buffer_type = MYSQL_TYPE_BIT;
+ buffer = &v;
+ buffer_length = 1;
+ }
+ void bind(int8_t &v)
+ {
+ init();
+ buffer_type = MYSQL_TYPE_TINY;
+ buffer = &v;
+ }
+ void bind(uint8_t &v)
+ {
+ init();
+ buffer_type = MYSQL_TYPE_TINY;
+ buffer = &v;
+ is_unsigned = true;
+ }
+ void bind(int16_t &v)
+ {
+ init();
+ buffer_type = MYSQL_TYPE_SHORT;
+ buffer = &v;
+ }
+ void bind(uint16_t &v)
+ {
+ init();
+ buffer_type = MYSQL_TYPE_SHORT;
+ buffer = &v;
+ is_unsigned = true;
+ }
+ void bind(int32_t &v)
+ {
+ init();
+ buffer_type = MYSQL_TYPE_LONG;
+ buffer = &v;
+ }
+ void bind(uint32_t &v)
+ {
+ init();
+ buffer_type = MYSQL_TYPE_LONG;
+ buffer = &v;
+ is_unsigned = true;
+ }
+ void bind(int64_t &v)
+ {
+ init();
+ buffer_type = MYSQL_TYPE_LONGLONG;
+ buffer = &v;
+ }
+ void bind(uint64_t &v)
+ {
+ init();
+ buffer_type = MYSQL_TYPE_LONGLONG;
+ buffer = &v;
+ is_unsigned = true;
+ }
+ void bind(double &v)
+ {
+ init();
+ buffer_type = MYSQL_TYPE_DOUBLE;
+ buffer = &v;
+ }
+ void bind(float &v)
+ {
+ init();
+ buffer_type = MYSQL_TYPE_FLOAT;
+ buffer = &v;
+ }
+ void bind(MYSQL_TIME &v, enum_field_types type = MYSQL_TYPE_TIMESTAMP)
+ {
+ init();
+ buffer_type = type;
+ buffer = &v;
+ }
+ void bind(void *data, unsigned long length, enum_field_types type = MYSQL_TYPE_BLOB)
+ {
+ init();
+ buffer_type = type;
+ buffer = data;
+ buffer_length = length;
+ }
+ void bind(const const_blob_data &data, enum_field_types type = MYSQL_TYPE_BLOB)
+ {
+ init();
+ buffer_type = type;
+ buffer = const_cast<void *>(data.data);
+ buffer_length = data.size;
+ }
+ void bind(blob_data &data, enum_field_types type = MYSQL_TYPE_BLOB)
+ {
+ init();
+ buffer_type = type;
+ buffer = data.data;
+ buffer_length = data.size;
+ }
+ };
+
+ template <typename T>
+ inline void bind(binder &binder, const T &v)
+ {
+ binder.bind(const_cast<T &>(v));
+ }
+
+ template <typename T>
+ inline void bind(binder &binder, T &&v)
+ {
+ binder.bind(v);
+ }
+
+ inline void bind(binder &binder, const char *str, size_t length = 0)
+ {
+ if (length == 0)
+ length = strlen(str);
+ binder.bind(const_cast<char *>(str), static_cast<unsigned long>(length), MYSQL_TYPE_VAR_STRING);
+ }
+
+ class base_statement;
+ class basic_database;
+
+ class error : public std::exception
+ {
+ public:
+ error() : m_error(0) {}
+ error(unsigned int err, const char *errmsg) : m_error(err), m_errmsg(errmsg) {}
+ explicit error(const base_statement &stmt);
+ explicit error(const basic_database &db);
+ error(const error &src) = default;
+ virtual ~error() throw() {}
+ int code() const throw() { return m_error; }
+ operator bool() const { return m_error != 0; }
+ virtual const char *what() const NOEXCEPT override { return m_errmsg.data(); }
+
+ private:
+ unsigned int m_error;
+ std::string m_errmsg;
+ };
+
+ class blobbuf : public qtl::blobbuf
+ {
+ public:
+ blobbuf() : m_stmt(nullptr), m_field(0)
+ {
+ }
+ blobbuf(const blobbuf &) = default;
+ blobbuf &operator=(const blobbuf &) = default;
+ virtual ~blobbuf() { overflow(); }
+
+ void open(MYSQL_STMT *stmt, int field, const binder &b, std::ios_base::openmode mode)
+ {
+ if (m_stmt && m_field)
{
- if (mysql_stmt_send_long_data(m_stmt, index, buffer.data(), readed) != 0)
- throw_exception();
+ overflow();
+ }
+
+ assert(stmt != nullptr);
+ m_stmt = stmt;
+ m_field = field;
+ m_binder = b;
+ if (b.length)
+ m_size = *b.length;
+ init_buffer(mode);
+ }
+
+ void swap(blobbuf &other)
+ {
+ std::swap(m_stmt, other.m_stmt);
+ std::swap(m_binder, other.m_binder);
+ std::swap(m_field, other.m_field);
+ qtl::blobbuf::swap(other);
+ }
+
+ private:
+ MYSQL_STMT *m_stmt;
+ binder m_binder;
+ int m_field;
+
+ protected:
+ virtual bool read_blob(char *buffer, off_type &count, pos_type position) override
+ {
+ m_binder.buffer = buffer;
+ m_binder.buffer_length = count;
+ int ret = mysql_stmt_fetch_column(m_stmt, &m_binder, m_field, position);
+ switch (ret)
+ {
+ case 0:
+ count = std::min(m_binder.buffer_length, *m_binder.length);
+ return true;
+ case CR_NO_DATA:
+ return false;
+ default:
+ throw error(mysql_stmt_errno(m_stmt), mysql_stmt_error(m_stmt));
}
}
- };
- }
- void bind_param(size_t index, const blob_writer& param)
- {
- m_binders[index].bind(nullptr, 0, MYSQL_TYPE_LONG_BLOB);
- m_binderAddins[index].m_after_fetch = [this, index, ¶m](const binder& b) {
- blobbuf buf;
- buf.open(m_stmt, index, b, std::ios::out);
- std::ostream s(&buf);
- param(s);
- };
- }
-
- template<class Param>
- void bind_param(size_t index, const Param& param)
- {
- bind(m_binders[index], param);
- }
-
- template<class Type>
- void bind_field(size_t index, Type&& value)
- {
- if (m_result)
- {
- bind(m_binders[index], std::forward<Type>(value));
- m_binderAddins[index].m_after_fetch =
- if_null<typename std::remove_reference<Type>::type>(value);
- }
- }
-
- void bind_field(size_t index, char* value, size_t length)
- {
- m_binders[index].bind(value, length - 1, MYSQL_TYPE_VAR_STRING);
- m_binderAddins[index].m_after_fetch = [](const binder& bind) {
- if (*bind.is_null)
- memset(bind.buffer, 0, bind.buffer_length + 1);
- else
+ virtual void write_blob(const char *buffer, size_t count) override
{
- char* text = reinterpret_cast<char*>(bind.buffer);
- text[*bind.length] = '\0';
+ int ret = mysql_stmt_send_long_data(m_stmt, m_field, buffer, count);
+ if (ret != 0)
+ throw error(mysql_stmt_errno(m_stmt), mysql_stmt_error(m_stmt));
}
};
- }
- template<size_t N>
- void bind_field(size_t index, std::array<char, N>&& value)
- {
- bind_field(index, value.data(), value.size());
- }
-
- template<typename T>
- void bind_field(size_t index, bind_string_helper<T>&& value)
- {
- if (m_result)
+ struct time : public MYSQL_TIME
{
- MYSQL_FIELD* field = mysql_fetch_field_direct(m_result, (unsigned int)index);
- if (field == nullptr) throw_exception();
- value.clear();
- typename bind_string_helper<T>::char_type* data = value.alloc(field->length);
- m_binderAddins[index].m_before_fetch = [this, value](binder& b) mutable {
- if (value.size() < b.buffer_length)
+ time()
+ {
+ memset(this, 0, sizeof(MYSQL_TIME));
+ time_type = MYSQL_TIMESTAMP_NONE;
+ }
+ time(const struct tm &tm)
+ {
+ memset(this, 0, sizeof(MYSQL_TIME));
+ year = tm.tm_year + 1900;
+ month = tm.tm_mon + 1;
+ day = tm.tm_mday;
+ hour = tm.tm_hour;
+ minute = tm.tm_min;
+ second = tm.tm_sec;
+ time_type = MYSQL_TIMESTAMP_DATETIME;
+ }
+ time(time_t value)
+ {
+ struct tm tm;
+#if defined(_MSC_VER)
+ localtime_s(&tm, &value);
+#elif defined(_POSIX_VERSION)
+ localtime_r(&value, &tm);
+#else
+ tm = *localtime(&value);
+#endif
+ new (this) time(tm);
+ }
+ time(const time &src)
+ {
+ memcpy(this, &src, sizeof(MYSQL_TIME));
+ }
+ time &operator=(const time &src)
+ {
+ if (this != &src)
+ memcpy(this, &src, sizeof(MYSQL_TIME));
+ return *this;
+ }
+
+ static time now()
+ {
+ time_t value;
+ ::time(&value);
+ return time(value);
+ }
+
+ time_t as_tm(struct tm &tm) const
+ {
+ tm.tm_year = year - 1900;
+ tm.tm_mon = month - 1;
+ tm.tm_mday = day;
+ tm.tm_hour = hour;
+ tm.tm_min = minute;
+ tm.tm_sec = second;
+ return mktime(&tm);
+ }
+ time_t get_time() const
+ {
+ struct tm tm;
+ return as_tm(tm);
+ }
+ };
+
+ class base_statement
+ {
+ protected:
+ base_statement() : m_stmt(nullptr), m_result(nullptr) {}
+ base_statement(const base_statement &) = delete;
+ explicit base_statement(basic_database &db);
+ base_statement(base_statement &&src)
+ : m_stmt(src.m_stmt), m_result(src.m_result),
+ m_binders(std::move(src.m_binders)), m_binderAddins(std::move(src.m_binderAddins))
+ {
+ src.m_stmt = nullptr;
+ src.m_result = nullptr;
+ }
+ base_statement &operator=(const base_statement &) = delete;
+ base_statement &operator=(base_statement &&src)
+ {
+ if (this != &src)
{
- value.alloc(b.buffer_length);
- if (b.buffer != value.data())
+ m_stmt = src.m_stmt;
+ m_result = src.m_result;
+ src.m_stmt = nullptr;
+ src.m_result = nullptr;
+ m_binders = std::move(src.m_binders);
+ m_binderAddins = std::move(src.m_binderAddins);
+ }
+ return *this;
+ }
+
+ public:
+ operator MYSQL_STMT *() { return m_stmt; }
+
+ unsigned int get_parameter_count() const { return mysql_stmt_param_count(m_stmt); }
+ unsigned int get_column_count() const { return mysql_stmt_field_count(m_stmt); }
+
+ unsigned long length(unsigned int index) const
+ {
+ return m_binderAddins[index].m_length;
+ }
+
+ bool is_null(unsigned int index) const
+ {
+ return m_binderAddins[index].m_isNull != 0;
+ }
+
+ size_t find_field(const char *name) const
+ {
+ if (m_result)
+ {
+ for (size_t i = 0; i != m_result->field_count; i++)
{
- b.buffer = const_cast<char*>(value.data());
- mysql_stmt_bind_result(m_stmt, &m_binders.front());
+ if (strncmp(m_result->fields[i].name, name, m_result->fields[i].name_length) == 0)
+ return i;
}
}
- };
- m_binderAddins[index].m_after_fetch = [value](const binder& b) mutable {
- if (*b.is_null) value.clear();
- else value.truncate(*b.length);
- };
- m_binders[index].bind((void*)data, field->length, field->type);
- }
- }
+ return -1;
+ }
- void bind_field(size_t index, std::ostream&& value)
- {
- if (m_result)
- {
- MYSQL_FIELD* field = mysql_fetch_field_direct(m_result, (unsigned int)index);
- assert(IS_LONGDATA(field->type));
- m_binders[index].bind(nullptr, 0, field->type);
- m_binderAddins[index].m_after_fetch = [this, index, &value](const binder& b) {
- unsigned long readed = 0;
- std::array<char, blob_buffer_size> buffer;
- binder& bb = const_cast<binder&>(b);
- if (*b.is_null) return;
- bb.buffer = const_cast<char*>(buffer.data());
- bb.buffer_length = buffer.size();
- while (readed <= *b.length)
+ my_ulonglong affetced_rows()
+ {
+ return mysql_stmt_affected_rows(m_stmt);
+ }
+ my_ulonglong insert_id()
+ {
+ return mysql_stmt_insert_id(m_stmt);
+ }
+
+ binder *get_binder(unsigned long index)
+ {
+ return &m_binders[index];
+ }
+
+ unsigned int error() const
+ {
+ return mysql_stmt_errno(m_stmt);
+ }
+ const char *errmsg() const
+ {
+ return mysql_stmt_error(m_stmt);
+ }
+
+ MYSQL_RES *result() { return m_result; }
+
+ void bind_param(size_t index, const char *param, size_t length)
+ {
+ bind(m_binders[index], param, length);
+ }
+
+ void bind_param(size_t index, const std::nullptr_t &)
+ {
+ m_binders[index].bind();
+ }
+
+ void bind_param(size_t index, std::istream ¶m)
+ {
+ m_binders[index].bind(nullptr, 0, MYSQL_TYPE_LONG_BLOB);
+ m_binderAddins[index].m_after_fetch = [this, index, ¶m](const binder &)
{
- int ret = mysql_stmt_fetch_column(m_stmt, &bb, index, readed);
- if (ret != 0)
- throw_exception();
- value.write(buffer.data(), std::min(b.buffer_length, *b.length - b.offset));
- readed += bb.buffer_length;
+ std::array<char, blob_buffer_size> buffer;
+ unsigned long readed = 0;
+ while (!param.eof() && !param.fail())
+ {
+ param.read(buffer.data(), buffer.size());
+ readed = (unsigned long)param.gcount();
+ if (readed > 0)
+ {
+ if (mysql_stmt_send_long_data(m_stmt, index, buffer.data(), readed) != 0)
+ throw_exception();
+ }
+ }
+ };
+ }
+
+ void bind_param(size_t index, const blob_writer ¶m)
+ {
+ m_binders[index].bind(nullptr, 0, MYSQL_TYPE_LONG_BLOB);
+ m_binderAddins[index].m_after_fetch = [this, index, ¶m](const binder &b)
+ {
+ blobbuf buf;
+ buf.open(m_stmt, index, b, std::ios::out);
+ std::ostream s(&buf);
+ param(s);
+ };
+ }
+
+ template <class Param>
+ void bind_param(size_t index, const Param ¶m)
+ {
+ bind(m_binders[index], param);
+ }
+
+ template <class Type>
+ void bind_field(size_t index, Type &&value)
+ {
+ if (m_result)
+ {
+ bind(m_binders[index], std::forward<Type>(value));
+ m_binderAddins[index].m_after_fetch =
+ if_null<typename std::remove_reference<Type>::type>(value);
}
- };
- }
- }
+ }
- void bind_field(size_t index, blobbuf&& value)
- {
- if (m_result)
- {
- MYSQL_FIELD* field = mysql_fetch_field_direct(m_result, (unsigned int)index);
- assert(IS_LONGDATA(field->type));
- m_binders[index].bind(nullptr, 0, field->type);
- m_binderAddins[index].m_after_fetch = [this, index, &value](const binder& b) {
- if (*b.is_null) return;
- value.open(m_stmt, index, b, std::ios::in);
- };
- }
- }
+ void bind_field(size_t index, char *value, size_t length)
+ {
+ m_binders[index].bind(value, length - 1, MYSQL_TYPE_VAR_STRING);
+ m_binderAddins[index].m_after_fetch = [](const binder &bind)
+ {
+ if (*bind.is_null)
+ memset(bind.buffer, 0, bind.buffer_length + 1);
+ else
+ {
+ char *text = reinterpret_cast<char *>(bind.buffer);
+ text[*bind.length] = '\0';
+ }
+ };
+ }
- template<typename Type>
- void bind_field(size_t index, indicator<Type>&& value)
- {
- if (m_result)
- {
- qtl::bind_field(*this, index, value.data);
- binder_addin& addin = m_binderAddins[index];
- auto fetch_fun = addin.m_after_fetch;
- addin.m_after_fetch = [&addin, fetch_fun, &value](const binder& b) {
- value.is_null = *b.is_null != 0;
- value.length = *b.length;
- value.is_truncated = addin.is_truncated;
- if (fetch_fun) fetch_fun(b);
- };
- }
- }
+ template <size_t N>
+ void bind_field(size_t index, std::array<char, N> &&value)
+ {
+ bind_field(index, value.data(), value.size());
+ }
+
+ template <typename T>
+ void bind_field(size_t index, bind_string_helper<T> &&value)
+ {
+ if (m_result)
+ {
+ MYSQL_FIELD *field = mysql_fetch_field_direct(m_result, (unsigned int)index);
+ if (field == nullptr)
+ throw_exception();
+ value.clear();
+ typename bind_string_helper<T>::char_type *data = value.alloc(field->length);
+ m_binderAddins[index].m_before_fetch = [this, value](binder &b) mutable
+ {
+ if (value.size() < b.buffer_length)
+ {
+ value.alloc(b.buffer_length);
+ if (b.buffer != value.data())
+ {
+ b.buffer = const_cast<char *>(value.data());
+ mysql_stmt_bind_result(m_stmt, &m_binders.front());
+ }
+ }
+ };
+ m_binderAddins[index].m_after_fetch = [value](const binder &b) mutable
+ {
+ if (*b.is_null)
+ value.clear();
+ else
+ value.truncate(*b.length);
+ };
+ m_binders[index].bind((void *)data, field->length, field->type);
+ }
+ }
+
+ void bind_field(size_t index, std::ostream &&value)
+ {
+ if (m_result)
+ {
+ MYSQL_FIELD *field = mysql_fetch_field_direct(m_result, (unsigned int)index);
+ assert(IS_LONGDATA(field->type));
+ m_binders[index].bind(nullptr, 0, field->type);
+ m_binderAddins[index].m_after_fetch = [this, index, &value](const binder &b)
+ {
+ unsigned long readed = 0;
+ std::array<char, blob_buffer_size> buffer;
+ binder &bb = const_cast<binder &>(b);
+ if (*b.is_null)
+ return;
+ bb.buffer = const_cast<char *>(buffer.data());
+ bb.buffer_length = buffer.size();
+ while (readed <= *b.length)
+ {
+ int ret = mysql_stmt_fetch_column(m_stmt, &bb, index, readed);
+ if (ret != 0)
+ throw_exception();
+ value.write(buffer.data(), std::min(b.buffer_length, *b.length - b.offset));
+ readed += bb.buffer_length;
+ }
+ };
+ }
+ }
+
+ void bind_field(size_t index, blobbuf &&value)
+ {
+ if (m_result)
+ {
+ MYSQL_FIELD *field = mysql_fetch_field_direct(m_result, (unsigned int)index);
+ assert(IS_LONGDATA(field->type));
+ m_binders[index].bind(nullptr, 0, field->type);
+ m_binderAddins[index].m_after_fetch = [this, index, &value](const binder &b)
+ {
+ if (*b.is_null)
+ return;
+ value.open(m_stmt, index, b, std::ios::in);
+ };
+ }
+ }
+
+ template <typename Type>
+ void bind_field(size_t index, indicator<Type> &&value)
+ {
+ if (m_result)
+ {
+ qtl::bind_field(*this, index, value.data);
+ binder_addin &addin = m_binderAddins[index];
+ auto fetch_fun = addin.m_after_fetch;
+ addin.m_after_fetch = [&addin, fetch_fun, &value](const binder &b)
+ {
+ value.is_null = *b.is_null != 0;
+ value.length = *b.length;
+ value.is_truncated = addin.is_truncated;
+ if (fetch_fun)
+ fetch_fun(b);
+ };
+ }
+ }
#ifdef _QTL_ENABLE_CPP17
- template<typename T>
- inline void bind_field(size_t index, std::optional<T>&& value)
- {
- if (m_result)
- {
- qtl::bind_field(*this, index, *value);
- binder_addin& addin = m_binderAddins[index];
- auto fetch_fun = addin.m_after_fetch;
- addin.m_after_fetch = [&addin, fetch_fun, &value](const binder& b) {
- if (fetch_fun) fetch_fun(b);
- if (*b.is_null) value.reset();
- };
- }
- }
-
- inline void bind_field(size_t index, std::any&& value)
- {
- if (m_result)
- {
- MYSQL_FIELD* field = mysql_fetch_field_direct(m_result, (unsigned int)index);
- if (field == nullptr) throw_exception();
- switch (field->type)
+ template <typename T>
+ inline void bind_field(size_t index, std::optional<T> &&value)
{
- case MYSQL_TYPE_NULL:
- value.reset();
- break;
- case MYSQL_TYPE_BIT:
- value.emplace<bool>();
- bind_field(index, std::any_cast<bool&>(value));
- break;
- case MYSQL_TYPE_TINY:
- value.emplace<int8_t>();
- bind_field(index, std::any_cast<int8_t&>(value));
- break;
- case MYSQL_TYPE_SHORT:
- value.emplace<int16_t>();
- bind_field(index, std::any_cast<int16_t&>(value));
- break;
- case MYSQL_TYPE_LONG:
- value.emplace<int32_t>();
- bind_field(index, std::any_cast<int32_t&>(value));
- break;
- case MYSQL_TYPE_LONGLONG:
- value.emplace<int64_t>();
- bind_field(index, std::any_cast<int64_t&>(value));
- break;
- case MYSQL_TYPE_FLOAT:
- value.emplace<float>();
- bind_field(index, std::any_cast<float&>(value));
- break;
- case MYSQL_TYPE_DOUBLE:
- value.emplace<double>();
- bind_field(index, std::any_cast<double&>(value));
- break;
- case MYSQL_TYPE_DATE:
- case MYSQL_TYPE_TIME:
- case MYSQL_TYPE_DATETIME:
- case MYSQL_TYPE_TIMESTAMP:
- case MYSQL_TYPE_TIMESTAMP2:
- case MYSQL_TYPE_DATETIME2:
- case MYSQL_TYPE_TIME2:
- value.emplace<qtl::mysql::time>();
- bind_field(index, std::any_cast<qtl::mysql::time&>(value));
- break;
- case MYSQL_TYPE_VARCHAR:
- case MYSQL_TYPE_VAR_STRING:
- case MYSQL_TYPE_STRING:
- case MYSQL_TYPE_ENUM:
-#if LIBMYSQL_VERSION_ID >= 50700
- case MYSQL_TYPE_JSON:
-#endif
- case MYSQL_TYPE_DECIMAL:
- case MYSQL_TYPE_NEWDECIMAL:
- case MYSQL_TYPE_GEOMETRY:
- value.emplace<std::string>();
- bind_field(index, qtl::bind_string(std::any_cast<std::string&>(value)));
- break;
- case MYSQL_TYPE_TINY_BLOB:
- case MYSQL_TYPE_MEDIUM_BLOB:
- case MYSQL_TYPE_BLOB:
- case MYSQL_TYPE_LONG_BLOB:
- value.emplace<blobbuf>();
- bind_field(index, std::forward<blobbuf>(std::any_cast<blobbuf&>(value)));
- break;
- default:
- throw mysql::error(CR_UNSUPPORTED_PARAM_TYPE, "Unsupported field type");
+ if (m_result)
+ {
+ qtl::bind_field(*this, index, *value);
+ binder_addin &addin = m_binderAddins[index];
+ auto fetch_fun = addin.m_after_fetch;
+ addin.m_after_fetch = [&addin, fetch_fun, &value](const binder &b)
+ {
+ if (fetch_fun)
+ fetch_fun(b);
+ if (*b.is_null)
+ value.reset();
+ };
+ }
}
- binder_addin& addin = m_binderAddins[index];
- auto fetch_fun = addin.m_after_fetch;
- addin.m_after_fetch = [&addin, fetch_fun, &value](const binder& b) {
- if (fetch_fun) fetch_fun(b);
- if (*b.is_null) value.reset();
- };
- }
- }
+
+ inline void bind_field(size_t index, std::any &&value)
+ {
+ if (m_result)
+ {
+ MYSQL_FIELD *field = mysql_fetch_field_direct(m_result, (unsigned int)index);
+ if (field == nullptr)
+ throw_exception();
+ switch (field->type)
+ {
+ case MYSQL_TYPE_NULL:
+ value.reset();
+ break;
+ case MYSQL_TYPE_BIT:
+ value.emplace<bool>();
+ bind_field(index, std::any_cast<bool &>(value));
+ break;
+ case MYSQL_TYPE_TINY:
+ value.emplace<int8_t>();
+ bind_field(index, std::any_cast<int8_t &>(value));
+ break;
+ case MYSQL_TYPE_SHORT:
+ value.emplace<int16_t>();
+ bind_field(index, std::any_cast<int16_t &>(value));
+ break;
+ case MYSQL_TYPE_LONG:
+ value.emplace<int32_t>();
+ bind_field(index, std::any_cast<int32_t &>(value));
+ break;
+ case MYSQL_TYPE_LONGLONG:
+ value.emplace<int64_t>();
+ bind_field(index, std::any_cast<int64_t &>(value));
+ break;
+ case MYSQL_TYPE_FLOAT:
+ value.emplace<float>();
+ bind_field(index, std::any_cast<float &>(value));
+ break;
+ case MYSQL_TYPE_DOUBLE:
+ value.emplace<double>();
+ bind_field(index, std::any_cast<double &>(value));
+ break;
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_TIMESTAMP2:
+ case MYSQL_TYPE_DATETIME2:
+ case MYSQL_TYPE_TIME2:
+ value.emplace<qtl::mysql::time>();
+ bind_field(index, std::any_cast<qtl::mysql::time &>(value));
+ break;
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_ENUM:
+#if LIBMYSQL_VERSION_ID >= 50700
+ case MYSQL_TYPE_JSON:
+#endif
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
+ case MYSQL_TYPE_GEOMETRY:
+ value.emplace<std::string>();
+ bind_field(index, qtl::bind_string(std::any_cast<std::string &>(value)));
+ break;
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ value.emplace<blobbuf>();
+ bind_field(index, std::forward<blobbuf>(std::any_cast<blobbuf &>(value)));
+ break;
+ default:
+ throw mysql::error(CR_UNSUPPORTED_PARAM_TYPE, "Unsupported field type");
+ }
+ binder_addin &addin = m_binderAddins[index];
+ auto fetch_fun = addin.m_after_fetch;
+ addin.m_after_fetch = [&addin, fetch_fun, &value](const binder &b)
+ {
+ if (fetch_fun)
+ fetch_fun(b);
+ if (*b.is_null)
+ value.reset();
+ };
+ }
+ }
#endif // C++17
- void close()
- {
- if (m_result)
- {
- mysql_free_result(m_result);
- m_result = nullptr;
- }
- if (m_stmt)
- {
- mysql_stmt_close(m_stmt);
- m_stmt = nullptr;
- }
- }
-
-protected:
- MYSQL_STMT* m_stmt;
- MYSQL_RES* m_result;
- std::vector<binder> m_binders;
-
- struct binder_addin
- {
- unsigned long m_length;
- my_bool m_isNull;
- my_bool m_error;
- bool is_truncated;
- std::function<void(binder&)> m_before_fetch;
- std::function<void(const binder&)> m_after_fetch;
- };
- std::vector<binder_addin> m_binderAddins;
-
- void resize_binders(size_t n)
- {
- m_binders.resize(n);
- m_binderAddins.resize(n);
- }
- void set_binders()
- {
- for(size_t i=0; i!=m_binders.size(); i++)
- {
- m_binderAddins[i].m_length=0;
- m_binders[i].length=&m_binderAddins[i].m_length;
- m_binderAddins[i].m_isNull=0;
- m_binders[i].is_null=&m_binderAddins[i].m_isNull;
- m_binderAddins[i].m_error=0;
- m_binders[i].error=&m_binderAddins[i].m_error;
- }
- }
-
- void throw_exception() const { throw mysql::error(*this); }
-
- template<typename Value>
- struct if_null
- {
- explicit if_null(Value& value, Value&& def=Value()) : m_value(value), m_def(std::move(def)) { }
- void operator()(const binder& b)
- {
- if(*b.is_null) m_value=m_def;
- }
- Value& m_value;
- Value m_def;
- };
-
-};
-
-class statement : public base_statement
-{
-public:
- statement() = default;
- explicit statement(basic_database& db) : base_statement(db) { }
- statement(statement&& src) : base_statement(std::move(src)) { }
- statement& operator=(statement&& src)
- {
- base_statement::operator =(std::move(src));
- return *this;
- }
- ~statement()
- {
- close();
- }
-
- void open(const char *query_text, unsigned long text_length=0)
- {
- mysql_stmt_reset(m_stmt);
- if(text_length==0) text_length=(unsigned long)strlen(query_text);
- if(mysql_stmt_prepare(m_stmt, query_text, text_length)!=0)
- throw_exception();
- }
-
- void execute()
- {
- resize_binders(0);
- if(mysql_stmt_execute(m_stmt)!=0)
- throw_exception();
- }
-
- template<typename BindProc>
- void execute_custom(BindProc&& bind_proc)
- {
- unsigned long count = mysql_stmt_param_count(m_stmt);
- if (count > 0)
- {
- resize_binders(count);
- bind_proc(*this);
- if (mysql_stmt_bind_param(m_stmt, &m_binders.front()))
- throw_exception();
- for (size_t i = 0; i != count; i++)
+ void close()
{
- if (m_binderAddins[i].m_after_fetch)
- m_binderAddins[i].m_after_fetch(m_binders[i]);
+ if (m_result)
+ {
+ mysql_free_result(m_result);
+ m_result = nullptr;
+ }
+ if (m_stmt)
+ {
+ mysql_stmt_close(m_stmt);
+ m_stmt = nullptr;
+ }
}
- }
- if (mysql_stmt_execute(m_stmt) != 0)
- throw_exception();
- }
- template<typename Types>
- void execute(const Types& params)
- {
- execute_custom([¶ms](statement& stmt) {
- qtl::bind_params(stmt, params);
- });
- }
+ protected:
+ MYSQL_STMT *m_stmt;
+ MYSQL_RES *m_result;
+ std::vector<binder> m_binders;
- template<typename Types>
- bool fetch(Types&& values)
- {
- if(m_result==nullptr)
- {
- unsigned long count=mysql_stmt_field_count(m_stmt);
- if(count>0)
+ struct binder_addin
{
- m_result=mysql_stmt_result_metadata(m_stmt);
- if(m_result==nullptr) throw_exception();
- resize_binders(count);
- qtl::bind_record(*this, std::forward<Types>(values));
- set_binders();
- if(mysql_stmt_bind_result(m_stmt, m_binders.data())!=0)
+ unsigned long m_length;
+ my_bool m_isNull;
+ my_bool m_error;
+ bool is_truncated;
+ std::function<void(binder &)> m_before_fetch;
+ std::function<void(const binder &)> m_after_fetch;
+ };
+ std::vector<binder_addin> m_binderAddins;
+
+ void resize_binders(size_t n)
+ {
+ m_binders.resize(n);
+ m_binderAddins.resize(n);
+ }
+ void set_binders()
+ {
+ for (size_t i = 0; i != m_binders.size(); i++)
+ {
+ m_binderAddins[i].m_length = 0;
+ m_binders[i].length = &m_binderAddins[i].m_length;
+ m_binderAddins[i].m_isNull = 0;
+ m_binders[i].is_null = &m_binderAddins[i].m_isNull;
+ m_binderAddins[i].m_error = 0;
+ m_binders[i].error = &m_binderAddins[i].m_error;
+ }
+ }
+
+ void throw_exception() const { throw mysql::error(*this); }
+
+ template <typename Value>
+ struct if_null
+ {
+ explicit if_null(Value &value, Value &&def = Value()) : m_value(value), m_def(std::move(def)) {}
+ void operator()(const binder &b)
+ {
+ if (*b.is_null)
+ m_value = m_def;
+ }
+ Value &m_value;
+ Value m_def;
+ };
+ };
+
+ class statement : public base_statement
+ {
+ public:
+ statement() = default;
+ explicit statement(basic_database &db) : base_statement(db) {}
+ statement(statement &&src) : base_statement(std::move(src)) {}
+ statement &operator=(statement &&src)
+ {
+ base_statement::operator=(std::move(src));
+ return *this;
+ }
+ ~statement()
+ {
+ close();
+ }
+
+ void open(const char *query_text, unsigned long text_length = 0)
+ {
+ mysql_stmt_reset(m_stmt);
+ if (text_length == 0)
+ text_length = (unsigned long)strlen(query_text);
+ if (mysql_stmt_prepare(m_stmt, query_text, text_length) != 0)
throw_exception();
}
- }
- return fetch();
- }
- bool fetch()
- {
- for (size_t i = 0; i != m_binders.size(); i++)
- {
- if (m_binderAddins[i].m_before_fetch)
- m_binderAddins[i].m_before_fetch(m_binders[i]);
- }
- int err=mysql_stmt_fetch(m_stmt);
- if(err==0 || err==MYSQL_DATA_TRUNCATED)
- {
- for(size_t i=0; i!=m_binders.size(); i++)
+ void execute()
{
- m_binderAddins[i].is_truncated = (err==MYSQL_DATA_TRUNCATED);
- if(m_binderAddins[i].m_after_fetch)
- m_binderAddins[i].m_after_fetch(m_binders[i]);
+ resize_binders(0);
+ if (mysql_stmt_execute(m_stmt) != 0)
+ throw_exception();
}
- return true;
- }
- else if(err==1)
- throw_exception();
- return false;
- }
- bool next_result()
- {
- if(m_result)
+ template <typename BindProc>
+ void execute_custom(BindProc &&bind_proc)
+ {
+ unsigned long count = mysql_stmt_param_count(m_stmt);
+ if (count > 0)
+ {
+ resize_binders(count);
+ bind_proc(*this);
+ if (mysql_stmt_bind_param(m_stmt, &m_binders.front()))
+ throw_exception();
+ for (size_t i = 0; i != count; i++)
+ {
+ if (m_binderAddins[i].m_after_fetch)
+ m_binderAddins[i].m_after_fetch(m_binders[i]);
+ }
+ }
+ if (mysql_stmt_execute(m_stmt) != 0)
+ throw_exception();
+ }
+
+ template <typename Types>
+ void execute(const Types ¶ms)
+ {
+ execute_custom([¶ms](statement &stmt)
+ { qtl::bind_params(stmt, params); });
+ }
+
+ template <typename Types>
+ bool fetch(Types &&values)
+ {
+ if (m_result == nullptr)
+ {
+ unsigned long count = mysql_stmt_field_count(m_stmt);
+ if (count > 0)
+ {
+ m_result = mysql_stmt_result_metadata(m_stmt);
+ if (m_result == nullptr)
+ throw_exception();
+ resize_binders(count);
+ qtl::bind_record(*this, std::forward<Types>(values));
+ set_binders();
+ if (mysql_stmt_bind_result(m_stmt, m_binders.data()) != 0)
+ throw_exception();
+ }
+ }
+ return fetch();
+ }
+
+ bool fetch()
+ {
+ for (size_t i = 0; i != m_binders.size(); i++)
+ {
+ if (m_binderAddins[i].m_before_fetch)
+ m_binderAddins[i].m_before_fetch(m_binders[i]);
+ }
+ int err = mysql_stmt_fetch(m_stmt);
+ if (err == 0 || err == MYSQL_DATA_TRUNCATED)
+ {
+ for (size_t i = 0; i != m_binders.size(); i++)
+ {
+ m_binderAddins[i].is_truncated = (err == MYSQL_DATA_TRUNCATED);
+ if (m_binderAddins[i].m_after_fetch)
+ m_binderAddins[i].m_after_fetch(m_binders[i]);
+ }
+ return true;
+ }
+ else if (err == 1)
+ throw_exception();
+ return false;
+ }
+
+ bool next_result()
+ {
+ if (m_result)
+ {
+ mysql_free_result(m_result);
+ m_result = nullptr;
+ mysql_stmt_free_result(m_stmt);
+ }
+ int ret = 0;
+ do
+ {
+ ret = mysql_stmt_next_result(m_stmt);
+ if (ret > 0)
+ throw_exception();
+ } while (ret == 0 && mysql_stmt_field_count(m_stmt) <= 0);
+ return ret == 0;
+ }
+
+ bool reset() { return mysql_stmt_reset(m_stmt) != 0; }
+ };
+
+ /*
+ struct LocalInfile
{
- mysql_free_result(m_result);
- m_result=nullptr;
- mysql_stmt_free_result(m_stmt);
- }
- int ret=0;
- do
+ int read(char *buf, unsigned int buf_len);
+ void close();
+ int error(char *error_msg, unsigned int error_msg_len);
+ };
+ */
+ template <typename LocalInfile>
+ struct local_infile_factory
{
- ret=mysql_stmt_next_result(m_stmt);
- if(ret>0) throw_exception();
- }while(ret==0 && mysql_stmt_field_count(m_stmt)<=0);
- return ret==0;
- }
+ static int local_infile_init(void **ptr, const char *filename, void *userdata)
+ {
+ LocalInfile *object = nullptr;
+ try
+ {
+ object = new LocalInfile(filename);
+ }
+ catch (...)
+ {
+ return -1;
+ }
+ return ptr ? 0 : -1;
+ }
- bool reset() { return mysql_stmt_reset(m_stmt)!=0; }
-};
+ static int local_infile_read(void *ptr, char *buf, unsigned int buf_len)
+ {
+ LocalInfile *object = reinterpret_cast<LocalInfile>(ptr);
+ return object->read(buf, buf_len);
+ }
-/*
-struct LocalInfile
-{
- int read(char *buf, unsigned int buf_len);
- void close();
- int error(char *error_msg, unsigned int error_msg_len);
-};
-*/
-template<typename LocalInfile>
-struct local_infile_factory
-{
- static int local_infile_init(void **ptr, const char *filename, void *userdata)
- {
- LocalInfile* object = nullptr;
- try
+ static void local_infile_end(void *ptr)
+ {
+ LocalInfile *object = reinterpret_cast<LocalInfile>(ptr);
+ object->close();
+ delete object;
+ }
+
+ static int local_infile_error(void *ptr, char *error_msg, unsigned int error_msg_len)
+ {
+ LocalInfile *object = reinterpret_cast<LocalInfile>(ptr);
+ return object->error(error_msg, error_msg_len);
+ }
+ };
+
+ class local_file
{
- object = new LocalInfile(filename);
- }
- catch (...)
+ public:
+ local_file(const char *filename)
+ {
+ m_fp = fopen(filename, "rb");
+ if (m_fp == nullptr)
+ throw std::system_error(std::make_error_code(std::errc(errno)));
+ }
+ int read(char *buf, unsigned int buf_len)
+ {
+ return fread(buf, 1, buf_len, m_fp);
+ }
+ void close()
+ {
+ fclose(m_fp);
+ }
+ int error(char *error_msg, unsigned int error_msg_len)
+ {
+ int errcode = errno;
+ memset(error_msg, 0, error_msg_len);
+ strncpy(error_msg, strerror(errcode), error_msg_len - 1);
+ return errcode;
+ }
+
+ private:
+ FILE *m_fp;
+ };
+
+ class basic_database
{
- return -1;
- }
- return ptr ? 0 : -1;
- }
+ protected:
+ basic_database()
+ {
+ m_mysql = mysql_init(nullptr);
+ }
- static int local_infile_read(void *ptr, char *buf, unsigned int buf_len)
- {
- LocalInfile* object = reinterpret_cast<LocalInfile>(ptr);
- return object->read(buf, buf_len);
- }
+ public:
+ typedef mysql::error exception_type;
- static void local_infile_end(void *ptr)
- {
- LocalInfile* object = reinterpret_cast<LocalInfile>(ptr);
- object->close();
- delete object;
- }
+ ~basic_database()
+ {
+ if (m_mysql)
+ mysql_close(m_mysql);
+ }
+ basic_database(const basic_database &) = delete;
+ basic_database(basic_database &&src)
+ {
+ m_mysql = src.m_mysql;
+ src.m_mysql = nullptr;
+ }
+ basic_database &operator==(const basic_database &) = delete;
+ basic_database &operator==(basic_database &&src)
+ {
+ if (this != &src)
+ {
+ if (m_mysql)
+ mysql_close(m_mysql);
+ m_mysql = src.m_mysql;
+ src.m_mysql = nullptr;
+ }
+ return *this;
+ }
- static int local_infile_error(void *ptr, char *error_msg, unsigned int error_msg_len)
- {
- LocalInfile* object = reinterpret_cast<LocalInfile>(ptr);
- return object->error(error_msg, error_msg_len);
- }
-};
+ MYSQL *handle() { return m_mysql; }
-class local_file
-{
-public:
- local_file(const char* filename)
- {
- m_fp = fopen(filename, "rb");
- if (m_fp == nullptr)
- throw std::system_error(std::make_error_code(std::errc(errno)));
- }
- int read(char *buf, unsigned int buf_len)
- {
- return fread(buf, 1, buf_len, m_fp);
- }
- void close()
- {
- fclose(m_fp);
- }
- int error(char *error_msg, unsigned int error_msg_len)
- {
- int errcode = errno;
- memset(error_msg, 0, error_msg_len);
- strncpy(error_msg, strerror(errcode), error_msg_len - 1);
- return errcode;
- }
+ void options(enum mysql_option option, const void *arg)
+ {
+ if (mysql_options(m_mysql, option, arg) != 0)
+ throw_exception();
+ }
+ void charset_name(const char *charset)
+ {
+ if (mysql_set_character_set(m_mysql, charset) != 0)
+ throw_exception();
+ }
+ void protocol(mysql_protocol_type type)
+ {
+ return options(MYSQL_OPT_PROTOCOL, &type);
+ }
+ void reconnect(my_bool re)
+ {
+ return options(MYSQL_OPT_RECONNECT, &re);
+ }
-private:
- FILE* m_fp;
-};
+ const char *current() const
+ {
+ return m_mysql->db;
+ }
-class basic_database
-{
-protected:
- basic_database()
- {
- m_mysql = mysql_init(nullptr);
- }
+ unsigned int error() const
+ {
+ return mysql_errno(m_mysql);
+ }
+ const char *errmsg() const
+ {
+ return mysql_error(m_mysql);
+ }
-public:
- typedef mysql::error exception_type;
+ uint64_t affected_rows()
+ {
+ return mysql_affected_rows(m_mysql);
+ }
- ~basic_database()
- {
- if(m_mysql)
- mysql_close(m_mysql);
- }
- basic_database(const basic_database&) = delete;
- basic_database(basic_database&& src)
- {
- m_mysql=src.m_mysql;
- src.m_mysql=nullptr;
- }
- basic_database& operator==(const basic_database&) = delete;
- basic_database& operator==(basic_database&& src)
- {
- if(this!=&src)
+ unsigned int field_count()
+ {
+ return mysql_field_count(m_mysql);
+ }
+
+ uint64_t insert_id()
+ {
+ return mysql_insert_id(m_mysql);
+ }
+
+ protected:
+ MYSQL *m_mysql;
+ void throw_exception() { throw mysql::error(*this); }
+ };
+
+#if MARIADB_VERSION_ID >= 050500
+
+ class async_connection;
+
+#endif // MariaDB
+
+ class database : public basic_database, public qtl::base_database<database, statement>
{
- if(m_mysql)
+ public:
+ database() = default;
+
+ bool open(const char *host, const char *user, const char *passwd, const char *db,
+ unsigned long clientflag = 0, unsigned int port = 0, const char *unix_socket = nullptr)
+ {
+ if (m_mysql == nullptr)
+ m_mysql = mysql_init(nullptr);
+ return mysql_real_connect(m_mysql, host, user, passwd, db, port, unix_socket, clientflag) != nullptr;
+ }
+ void close()
+ {
mysql_close(m_mysql);
- m_mysql=src.m_mysql;
- src.m_mysql=nullptr;
- }
- return *this;
- }
-
- MYSQL* handle() { return m_mysql; }
-
- void options(enum mysql_option option, const void *arg)
- {
- if(mysql_options(m_mysql, option, arg)!=0)
- throw_exception();
- }
- void charset_name(const char* charset)
- {
- if(mysql_set_character_set(m_mysql, charset)!=0)
- throw_exception();
- }
- void protocol(mysql_protocol_type type)
- {
- return options(MYSQL_OPT_PROTOCOL, &type);
- }
- void reconnect(my_bool re)
- {
- return options(MYSQL_OPT_RECONNECT, &re);
- }
-
- const char* current() const
- {
- return m_mysql->db;
- }
-
- unsigned int error() const
- {
- return mysql_errno(m_mysql);
- }
- const char* errmsg() const
- {
- return mysql_error(m_mysql);
- }
-
- uint64_t affected_rows()
- {
- return mysql_affected_rows(m_mysql);
- }
-
- unsigned int field_count()
- {
- return mysql_field_count(m_mysql);
- }
-
- uint64_t insert_id()
- {
- return mysql_insert_id(m_mysql);
- }
-
-protected:
- MYSQL* m_mysql;
- void throw_exception() { throw mysql::error(*this); }
-};
-
-#if MARIADB_VERSION_ID >= 050500
-
-class async_connection;
-
-#endif //MariaDB
-
-class database : public basic_database, public qtl::base_database<database, statement>
-{
-public:
- database() = default;
-
- bool open(const char *host, const char *user, const char *passwd, const char *db,
- unsigned long clientflag = 0, unsigned int port = 0, const char *unix_socket = nullptr)
- {
- if (m_mysql == nullptr) m_mysql = mysql_init(nullptr);
- return mysql_real_connect(m_mysql, host, user, passwd, db, port, unix_socket, clientflag) != nullptr;
- }
- void close()
- {
- mysql_close(m_mysql);
- m_mysql = nullptr;
- }
-
- statement open_command(const char* query_text, size_t text_length)
- {
- statement stmt(*this);
- stmt.open(query_text, text_length);
- return stmt;
- }
- statement open_command(const char* query_text)
- {
- return open_command(query_text, strlen(query_text));
- }
- statement open_command(const std::string& query_text)
- {
- return open_command(query_text.data(), query_text.length());
- }
-
- void refresh(unsigned int options)
- {
- if (mysql_refresh(m_mysql, options) < 0)
- throw_exception();
- }
-
- void select(const char* db)
- {
- if (mysql_select_db(m_mysql, db) != 0)
- throw_exception();
- }
-
- void simple_execute(const char* query_text, uint64_t* paffected = nullptr)
- {
- if (mysql_query(m_mysql, query_text) != 0)
- throw_exception();
- if (paffected) *paffected = affected_rows();
- }
- void simple_execute(const char* query_text, unsigned long text_length, uint64_t* paffected = nullptr)
- {
- if (text_length == 0) text_length = (unsigned long)strlen(query_text);
- if (mysql_real_query(m_mysql, query_text, text_length) != 0)
- throw_exception();
- if (paffected) *paffected = affected_rows();
- }
-
- void auto_commit(bool on)
- {
- if (mysql_autocommit(m_mysql, on ? 1 : 0) != 0)
- throw_exception();
- }
- void begin_transaction()
- {
- auto_commit(false);
- }
- void rollback()
- {
- if (mysql_rollback(m_mysql) != 0)
- throw_exception();
- auto_commit(true);
- }
- void commit()
- {
- if (mysql_commit(m_mysql) != 0)
- throw_exception();
- auto_commit(true);
- }
-
- bool is_alive()
- {
- return mysql_ping(m_mysql) == 0;
- }
-
- template<typename Pred>
- bool simple_query(const char* query, unsigned long length, Pred&& pred)
- {
- simple_execute(query, length);
-
- unsigned int fieldCount = mysql_field_count(m_mysql);
- MYSQL_RES* result = mysql_store_result(m_mysql);
- if (fieldCount > 0 && result)
- {
- MYSQL_RES* result = mysql_store_result(m_mysql);
- MYSQL_ROW row;
- while (row = mysql_fetch_row(result))
- {
- if (!pred(*this, row, fieldCount))
- break;
+ m_mysql = nullptr;
}
- mysql_free_result(result);
- return true;
- }
- return false;
- }
- template<typename LocalInfile>
- void set_local_infile_factory(local_infile_factory<LocalInfile>* factory)
- {
- typedef local_infile_factory<LocalInfile> factory_type;
- if (factory == nullptr)
- {
- reset_local_infile();
- }
- else
- {
- mysql_set_local_infile_handler(m_mysql, &factory_type::local_infile_init,
- &factory_type::local_infile_read,
- &factory_type::local_infile_end,
- &factory_type::local_infile_error, factory);
- }
- }
- void reset_local_infile()
- {
- mysql_set_local_infile_default(m_mysql);
- }
+ statement open_command(const char *query_text, size_t text_length)
+ {
+ statement stmt(*this);
+ stmt.open(query_text, text_length);
+ return stmt;
+ }
+ statement open_command(const char *query_text)
+ {
+ return open_command(query_text, strlen(query_text));
+ }
+ statement open_command(const std::string &query_text)
+ {
+ return open_command(query_text.data(), query_text.length());
+ }
+
+ void refresh(unsigned int options)
+ {
+ if (mysql_refresh(m_mysql, options) < 0)
+ throw_exception();
+ }
+
+ void select(const char *db)
+ {
+ if (mysql_select_db(m_mysql, db) != 0)
+ throw_exception();
+ }
+
+ void simple_execute(const char *query_text, uint64_t *paffected = nullptr)
+ {
+ if (mysql_query(m_mysql, query_text) != 0)
+ throw_exception();
+ if (paffected)
+ *paffected = affected_rows();
+ }
+ void simple_execute(const char *query_text, unsigned long text_length, uint64_t *paffected = nullptr)
+ {
+ if (text_length == 0)
+ text_length = (unsigned long)strlen(query_text);
+ if (mysql_real_query(m_mysql, query_text, text_length) != 0)
+ throw_exception();
+ if (paffected)
+ *paffected = affected_rows();
+ }
+
+ void auto_commit(bool on)
+ {
+ if (mysql_autocommit(m_mysql, on ? 1 : 0) != 0)
+ throw_exception();
+ }
+ void begin_transaction()
+ {
+ auto_commit(false);
+ }
+ void rollback()
+ {
+ if (mysql_rollback(m_mysql) != 0)
+ throw_exception();
+ auto_commit(true);
+ }
+ void commit()
+ {
+ if (mysql_commit(m_mysql) != 0)
+ throw_exception();
+ auto_commit(true);
+ }
+
+ bool is_alive()
+ {
+ return mysql_ping(m_mysql) == 0;
+ }
+
+ template <typename Pred>
+ bool simple_query(const char *query, unsigned long length, Pred &&pred)
+ {
+ simple_execute(query, length);
+
+ unsigned int fieldCount = mysql_field_count(m_mysql);
+ MYSQL_RES *result = mysql_store_result(m_mysql);
+ if (fieldCount > 0 && result)
+ {
+ MYSQL_RES *result = mysql_store_result(m_mysql);
+ MYSQL_ROW row;
+ while (row = mysql_fetch_row(result))
+ {
+ if (!pred(*this, row, fieldCount))
+ break;
+ }
+ mysql_free_result(result);
+ return true;
+ }
+ return false;
+ }
+
+ template <typename LocalInfile>
+ void set_local_infile_factory(local_infile_factory<LocalInfile> *factory)
+ {
+ typedef local_infile_factory<LocalInfile> factory_type;
+ if (factory == nullptr)
+ {
+ reset_local_infile();
+ }
+ else
+ {
+ mysql_set_local_infile_handler(m_mysql, &factory_type::local_infile_init,
+ &factory_type::local_infile_read,
+ &factory_type::local_infile_end,
+ &factory_type::local_infile_error, factory);
+ }
+ }
+ void reset_local_infile()
+ {
+ mysql_set_local_infile_default(m_mysql);
+ }
#if MARIADB_VERSION_ID >= 050500
- async_connection async_mode();
+ async_connection async_mode();
-#endif //MariaDB
-
-};
+#endif // MariaDB
+ };
#if MARIADB_VERSION_ID >= 100000
-inline int event_flags(int status) NOEXCEPT
-{
- int flags = 0;
- if (status&MYSQL_WAIT_READ)
- flags |= event::ef_read;
- if (status&MYSQL_WAIT_WRITE)
- flags |= event::ef_write;
- if (status&MYSQL_WAIT_EXCEPT)
- flags |= event::ef_exception;
- return flags;
-}
-
-inline int mysql_status(int flags) NOEXCEPT
-{
- int status = 0;
- if (flags&event::ef_read)
- status |= MYSQL_WAIT_READ;
- if (flags&event::ef_write)
- status |= MYSQL_WAIT_WRITE;
- if (flags&event::ef_exception)
- status |= MYSQL_WAIT_EXCEPT;
- if (flags&event::ef_timeout)
- status |= MYSQL_WAIT_TIMEOUT;
- return status;
-}
-
-class async_connection;
-
-class async_statement : public base_statement
-{
-public:
- async_statement() = default;
- async_statement(async_connection& db);
- async_statement(async_statement&& src)
- : base_statement(std::move(src))
- {
- m_event=src.m_event;
- src.m_event=nullptr;
- }
- async_statement& operator=(async_statement&& src)
- {
- base_statement::operator =(std::move(src));
- m_event=src.m_event;
- src.m_event=nullptr;
- return *this;
- }
- ~async_statement()
- {
- close();
- }
-
- /*
- Handler defiens as:
- void handler(const qtl::mysql::error& e);
- */
- template<typename Handler>
- void open(Handler&& handler, const char *query_text, size_t text_length=0)
- {
- if(text_length==0) text_length=strlen(query_text);
- if(m_stmt)
+ inline int event_flags(int status) NOEXCEPT
{
- std::string text(query_text, text_length);
- reset([this, text, handler](const mysql::error& e) mutable {
+ int flags = 0;
+ if (status & MYSQL_WAIT_READ)
+ flags |= event::ef_read;
+ if (status & MYSQL_WAIT_WRITE)
+ flags |= event::ef_write;
+ if (status & MYSQL_WAIT_EXCEPT)
+ flags |= event::ef_exception;
+ return flags;
+ }
+
+ inline int mysql_status(int flags) NOEXCEPT
+ {
+ int status = 0;
+ if (flags & event::ef_read)
+ status |= MYSQL_WAIT_READ;
+ if (flags & event::ef_write)
+ status |= MYSQL_WAIT_WRITE;
+ if (flags & event::ef_exception)
+ status |= MYSQL_WAIT_EXCEPT;
+ if (flags & event::ef_timeout)
+ status |= MYSQL_WAIT_TIMEOUT;
+ return status;
+ }
+
+ class async_connection;
+
+ class async_statement : public base_statement
+ {
+ public:
+ async_statement() = default;
+ async_statement(async_connection &db);
+ async_statement(async_statement &&src)
+ : base_statement(std::move(src))
+ {
+ m_event = src.m_event;
+ src.m_event = nullptr;
+ }
+ async_statement &operator=(async_statement &&src)
+ {
+ base_statement::operator=(std::move(src));
+ m_event = src.m_event;
+ src.m_event = nullptr;
+ return *this;
+ }
+ ~async_statement()
+ {
+ close();
+ }
+
+ /*
+ Handler defiens as:
+ void handler(const qtl::mysql::error& e);
+ */
+ template <typename Handler>
+ void open(Handler &&handler, const char *query_text, size_t text_length = 0)
+ {
+ if (text_length == 0)
+ text_length = strlen(query_text);
+ if (m_stmt)
+ {
+ std::string text(query_text, text_length);
+ reset([this, text, handler](const mysql::error &e) mutable
+ {
if(e)
{
handler(e);
return;
}
- prepare(text.data(), text.size(), std::forward<Handler>(handler));
- });
- }
- else
- {
- prepare(query_text, text_length, std::forward<Handler>(handler));
- }
- }
-
- /*
- ExecuteHandler defiens as:
- void handler(const qtl::mysql::error& e, uint64_t affected);
- */
- template<typename ExecuteHandler>
- void execute(ExecuteHandler&& handler)
- {
- resize_binders(0);
- int ret=0;
- int status = mysql_stmt_execute_start(&ret, m_stmt);
- if(status)
- wait_execute(status, std::forward<ExecuteHandler>(handler));
- else if(ret)
- handler(mysql::error(*this), 0);
- else
- handler(mysql::error(), affetced_rows());
- }
-
- template<typename Types, typename Handler>
- void execute(const Types& params, Handler&& handler)
- {
- unsigned long count=mysql_stmt_param_count(m_stmt);
- if(count>0)
- {
- resize_binders(count);
- qtl::bind_params(*this, params);
- if(mysql_stmt_bind_param(m_stmt, &m_binders.front()))
- throw_exception();
- for(size_t i=0; i!=count; i++)
- {
- if(m_binderAddins[i].m_after_fetch)
- m_binderAddins[i].m_after_fetch(m_binders[i]);
- }
- }
- execute(std::forward<Handler>(handler));
- }
-
- template<typename Types, typename RowHandler, typename FinishHandler>
- void fetch(Types&& values, RowHandler&& row_handler, FinishHandler&& finish_handler)
- {
- if(m_result==nullptr)
- {
- unsigned long count=mysql_stmt_field_count(m_stmt);
- if(count>0)
- {
- m_result=mysql_stmt_result_metadata(m_stmt);
- if(m_result==nullptr) throw_exception();
- resize_binders(count);
- qtl::bind_record(*this, std::forward<Types>(values));
- set_binders();
- if(mysql_stmt_bind_result(m_stmt, m_binders.data())!=0)
+ prepare(text.data(), text.size(), std::forward<Handler>(handler)); });
+ }
+ else
{
- finish_handler(mysql::error(*this));
- return;
+ prepare(query_text, text_length, std::forward<Handler>(handler));
}
}
- }
- fetch(std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
- }
- template<typename RowHandler, typename FinishHandler>
- void fetch(RowHandler&& row_handler, FinishHandler&& finish_handler)
- {
- int ret = 0;
- int status = start_fetch(&ret);
- if (status == 0)
- status = after_fetch(status, ret, std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
- if (status)
- wait_fetch(status, std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
- }
-
- template<typename Handler>
- void reset(Handler&& handler)
- {
- my_bool ret=false;
- int status = mysql_stmt_reset_start(&ret, m_stmt);
- if(status)
- wait_operation<my_bool>(status, &mysql_stmt_reset_cont, handler);
- else
- handler( (ret) ? mysql::error(*this) : mysql::error());
- }
-
- void close()
- {
- base_statement::close();
- }
-
- template<typename Handler>
- void close(Handler&& handler)
- {
- if(m_result)
- {
- my_bool ret=0;
- int status = mysql_stmt_free_result_start(&ret, m_stmt);
- if(status)
+ /*
+ ExecuteHandler defiens as:
+ void handler(const qtl::mysql::error& e, uint64_t affected);
+ */
+ template <typename ExecuteHandler>
+ void execute(ExecuteHandler &&handler)
{
- this->wait_free_result(status, [this, handler](const mysql::error& e) mutable {
- m_result=nullptr;
- if (e)
- handler(e);
- else
- close(handler);
- });
- }
- else if(ret)
- handler(mysql::error(*this));
- else
- m_result=nullptr;
- }
- if(m_stmt)
- {
- my_bool ret=0;
- int status = mysql_stmt_close_start(&ret, m_stmt);
- if(status)
- {
- wait_operation<my_bool>(status, &mysql_stmt_close_cont, [this, handler](const mysql::error& e) mutable {
- m_stmt=nullptr;
- handler(e);
- });;
- }
- else
- {
- m_stmt = nullptr;
- handler((ret) ? mysql::error(*this) : mysql::error());
- }
- }
- }
-
- template<typename Handler>
- void next_result(Handler&& handler)
- {
- if(m_result)
- {
- mysql_free_result(m_result);
- m_result = nullptr;
- }
- int ret=0;
- do
- {
- int status = mysql_stmt_next_result_start(&ret, m_stmt);
- if (status)
- {
- wait_next_result(status, std::forward<Handler>(handler));
- return;
- }
- }while(ret==0 && mysql_stmt_field_count(m_stmt)<=0);
- handler((ret) ? mysql::error(*this) : mysql::error());
- }
-
-
-private:
- event* m_event;
-
- template<typename Handler>
- void prepare(const char *query_text, size_t text_length, Handler&& handler)
- {
- int ret;
- int status=mysql_stmt_prepare_start(&ret, m_stmt, query_text, (unsigned long)text_length);
- if(status)
- wait_operation<int>(status, &mysql_stmt_prepare_cont, handler);
- else
- handler((ret) ? mysql::error(*this) : mysql::error());
- }
-
- template<typename Ret, typename Func, typename Handler>
- void wait_operation(int status, Func func, Handler&& handler)
- {
- m_event->set_io_handler(event_flags(status), mysql_get_timeout_value(m_stmt->mysql),
- [this, func, handler](int flags) mutable {
- Ret ret = 0;
- int status = func(&ret, m_stmt, mysql_status(flags));
- if (status)
- wait_operation<Ret>(status, func, handler);
- else
- handler((ret) ? mysql::error(*this) : mysql::error());
- });
- }
-
- template<typename ExecuteHandler>
- void wait_execute(int status, ExecuteHandler&& handler)
- {
- m_event->set_io_handler(event_flags(status), mysql_get_timeout_value(m_stmt->mysql),
- [this, handler](int flags) mutable {
+ resize_binders(0);
int ret = 0;
- int status = mysql_stmt_execute_cont(&ret, m_stmt, mysql_status(flags));
+ int status = mysql_stmt_execute_start(&ret, m_stmt);
if (status)
- wait_execute(status, handler);
- else if(ret)
+ wait_execute(status, std::forward<ExecuteHandler>(handler));
+ else if (ret)
handler(mysql::error(*this), 0);
else
handler(mysql::error(), affetced_rows());
- });
- }
+ }
- template<typename RowHandler, typename FinishHandler>
- void wait_fetch(int status, RowHandler&& row_handler, FinishHandler&& finish_handler)
- {
- m_event->set_io_handler(event_flags(status), mysql_get_timeout_value(m_stmt->mysql),
- [this, row_handler, finish_handler](int flags) mutable {
+ template <typename Types, typename Handler>
+ void execute(const Types ¶ms, Handler &&handler)
+ {
+ unsigned long count = mysql_stmt_param_count(m_stmt);
+ if (count > 0)
+ {
+ resize_binders(count);
+ qtl::bind_params(*this, params);
+ if (mysql_stmt_bind_param(m_stmt, &m_binders.front()))
+ throw_exception();
+ for (size_t i = 0; i != count; i++)
+ {
+ if (m_binderAddins[i].m_after_fetch)
+ m_binderAddins[i].m_after_fetch(m_binders[i]);
+ }
+ }
+ execute(std::forward<Handler>(handler));
+ }
+
+ template <typename Types, typename RowHandler, typename FinishHandler>
+ void fetch(Types &&values, RowHandler &&row_handler, FinishHandler &&finish_handler)
+ {
+ if (m_result == nullptr)
+ {
+ unsigned long count = mysql_stmt_field_count(m_stmt);
+ if (count > 0)
+ {
+ m_result = mysql_stmt_result_metadata(m_stmt);
+ if (m_result == nullptr)
+ throw_exception();
+ resize_binders(count);
+ qtl::bind_record(*this, std::forward<Types>(values));
+ set_binders();
+ if (mysql_stmt_bind_result(m_stmt, m_binders.data()) != 0)
+ {
+ finish_handler(mysql::error(*this));
+ return;
+ }
+ }
+ }
+ fetch(std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
+ }
+
+ template <typename RowHandler, typename FinishHandler>
+ void fetch(RowHandler &&row_handler, FinishHandler &&finish_handler)
+ {
int ret = 0;
- int status = mysql_stmt_fetch_cont(&ret, m_stmt, mysql_status(flags));
+ int status = start_fetch(&ret);
if (status == 0)
status = after_fetch(status, ret, std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
if (status)
wait_fetch(status, std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
- });
- }
+ }
- int start_fetch(int* ret)
- {
- for (size_t i = 0; i != m_binders.size(); i++)
- {
- if (m_binderAddins[i].m_before_fetch)
- m_binderAddins[i].m_before_fetch(m_binders[i]);
- }
- return mysql_stmt_fetch_start(ret, m_stmt);
- }
+ template <typename Handler>
+ void reset(Handler &&handler)
+ {
+ my_bool ret = false;
+ int status = mysql_stmt_reset_start(&ret, m_stmt);
+ if (status)
+ wait_operation<my_bool>(status, &mysql_stmt_reset_cont, handler);
+ else
+ handler((ret) ? mysql::error(*this) : mysql::error());
+ }
- template<typename RowHandler, typename FinishHandler>
- int after_fetch(int status, int ret, RowHandler&& row_handler, FinishHandler&& finish_handler)
- {
- while (status == 0)
- {
- if (ret == 0 || ret == MYSQL_DATA_TRUNCATED)
+ void close()
+ {
+ base_statement::close();
+ }
+
+ template <typename Handler>
+ void close(Handler &&handler)
+ {
+ if (m_result)
+ {
+ my_bool ret = 0;
+ int status = mysql_stmt_free_result_start(&ret, m_stmt);
+ if (status)
+ {
+ this->wait_free_result(status, [this, handler](const mysql::error &e) mutable
+ {
+ m_result=nullptr;
+ if (e)
+ handler(e);
+ else
+ close(handler); });
+ }
+ else if (ret)
+ handler(mysql::error(*this));
+ else
+ m_result = nullptr;
+ }
+ if (m_stmt)
+ {
+ my_bool ret = 0;
+ int status = mysql_stmt_close_start(&ret, m_stmt);
+ if (status)
+ {
+ wait_operation<my_bool>(status, &mysql_stmt_close_cont, [this, handler](const mysql::error &e) mutable
+ {
+ m_stmt=nullptr;
+ handler(e); });
+ ;
+ }
+ else
+ {
+ m_stmt = nullptr;
+ handler((ret) ? mysql::error(*this) : mysql::error());
+ }
+ }
+ }
+
+ template <typename Handler>
+ void next_result(Handler &&handler)
+ {
+ if (m_result)
+ {
+ mysql_free_result(m_result);
+ m_result = nullptr;
+ }
+ int ret = 0;
+ do
+ {
+ int status = mysql_stmt_next_result_start(&ret, m_stmt);
+ if (status)
+ {
+ wait_next_result(status, std::forward<Handler>(handler));
+ return;
+ }
+ } while (ret == 0 && mysql_stmt_field_count(m_stmt) <= 0);
+ handler((ret) ? mysql::error(*this) : mysql::error());
+ }
+
+ private:
+ event *m_event;
+
+ template <typename Handler>
+ void prepare(const char *query_text, size_t text_length, Handler &&handler)
+ {
+ int ret;
+ int status = mysql_stmt_prepare_start(&ret, m_stmt, query_text, (unsigned long)text_length);
+ if (status)
+ wait_operation<int>(status, &mysql_stmt_prepare_cont, handler);
+ else
+ handler((ret) ? mysql::error(*this) : mysql::error());
+ }
+
+ template <typename Ret, typename Func, typename Handler>
+ void wait_operation(int status, Func func, Handler &&handler)
+ {
+ m_event->set_io_handler(event_flags(status), mysql_get_timeout_value(m_stmt->mysql),
+ [this, func, handler](int flags) mutable
+ {
+ Ret ret = 0;
+ int status = func(&ret, m_stmt, mysql_status(flags));
+ if (status)
+ wait_operation<Ret>(status, func, handler);
+ else
+ handler((ret) ? mysql::error(*this) : mysql::error());
+ });
+ }
+
+ template <typename ExecuteHandler>
+ void wait_execute(int status, ExecuteHandler &&handler)
+ {
+ m_event->set_io_handler(event_flags(status), mysql_get_timeout_value(m_stmt->mysql),
+ [this, handler](int flags) mutable
+ {
+ int ret = 0;
+ int status = mysql_stmt_execute_cont(&ret, m_stmt, mysql_status(flags));
+ if (status)
+ wait_execute(status, handler);
+ else if (ret)
+ handler(mysql::error(*this), 0);
+ else
+ handler(mysql::error(), affetced_rows());
+ });
+ }
+
+ template <typename RowHandler, typename FinishHandler>
+ void wait_fetch(int status, RowHandler &&row_handler, FinishHandler &&finish_handler)
+ {
+ m_event->set_io_handler(event_flags(status), mysql_get_timeout_value(m_stmt->mysql),
+ [this, row_handler, finish_handler](int flags) mutable
+ {
+ int ret = 0;
+ int status = mysql_stmt_fetch_cont(&ret, m_stmt, mysql_status(flags));
+ if (status == 0)
+ status = after_fetch(status, ret, std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
+ if (status)
+ wait_fetch(status, std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
+ });
+ }
+
+ int start_fetch(int *ret)
{
for (size_t i = 0; i != m_binders.size(); i++)
{
- m_binderAddins[i].is_truncated = (ret == MYSQL_DATA_TRUNCATED);
- if (m_binderAddins[i].m_after_fetch)
- m_binderAddins[i].m_after_fetch(m_binders[i]);
+ if (m_binderAddins[i].m_before_fetch)
+ m_binderAddins[i].m_before_fetch(m_binders[i]);
}
- if (row_handler())
- status = start_fetch(&ret);
- else
+ return mysql_stmt_fetch_start(ret, m_stmt);
+ }
+
+ template <typename RowHandler, typename FinishHandler>
+ int after_fetch(int status, int ret, RowHandler &&row_handler, FinishHandler &&finish_handler)
+ {
+ while (status == 0)
{
- finish_handler(mysql::error());
- break;
- }
+ if (ret == 0 || ret == MYSQL_DATA_TRUNCATED)
+ {
+ for (size_t i = 0; i != m_binders.size(); i++)
+ {
+ m_binderAddins[i].is_truncated = (ret == MYSQL_DATA_TRUNCATED);
+ if (m_binderAddins[i].m_after_fetch)
+ m_binderAddins[i].m_after_fetch(m_binders[i]);
+ }
+ if (row_handler())
+ status = start_fetch(&ret);
+ else
+ {
+ finish_handler(mysql::error());
+ break;
+ }
+ }
+ else if (ret == 1)
+ {
+ finish_handler(mysql::error(*this));
+ break;
+ }
+ else
+ {
+ finish_handler(mysql::error());
+ break;
+ }
+ };
+ return status;
}
- else if (ret == 1)
+
+ template <typename ResultHandler>
+ void wait_free_result(int status, ResultHandler &&handler) NOEXCEPT
{
- finish_handler(mysql::error(*this));
- break;
+ m_event->set_io_handler(event_flags(status), mysql_get_timeout_value(m_stmt->mysql),
+ [this, handler](int flags) mutable
+ {
+ my_bool ret = false;
+ int status = mysql_stmt_free_result_cont(&ret, m_stmt, mysql_status(flags));
+ if (status)
+ wait_free_result(status, handler);
+ else
+ handler(mysql::error());
+ });
}
- else
+
+ template <typename Handler>
+ void wait_next_result(int status, Handler &&handler)
{
- finish_handler(mysql::error());
- break;
+ m_event->set_io_handler(event_flags(status), mysql_get_timeout_value(m_stmt->mysql),
+ [this, handler](int flags) mutable
+ {
+ int ret = 0;
+ int status = mysql_stmt_next_result_cont(&ret, m_stmt, mysql_status(flags));
+ if (status)
+ wait_next_result(status, handler);
+ else if (ret)
+ handler(mysql::error(*this));
+ else if (mysql_stmt_field_count(m_stmt) > 0)
+ handler(mysql::error());
+ else
+ next_result(std::forward<Handler>(handler));
+ });
}
};
- return status;
- }
- template<typename ResultHandler>
- void wait_free_result(int status, ResultHandler&& handler) NOEXCEPT
- {
- m_event->set_io_handler(event_flags(status), mysql_get_timeout_value(m_stmt->mysql),
- [this, handler](int flags) mutable {
- my_bool ret = false;
- int status = mysql_stmt_free_result_cont(&ret, m_stmt, mysql_status(flags));
+ class async_connection : public basic_database, public qtl::async_connection<async_connection, async_statement>
+ {
+ public:
+ async_connection() = default;
+
+ /*
+ OpenHandler defines as:
+ void handler(const qtl::mysql::error& e) NOEXCEPT;
+ */
+ template <typename EventLoop, typename OpenHandler>
+ void open(EventLoop &ev, OpenHandler &&handler, const char *host, const char *user, const char *passwd, const char *db,
+ unsigned long clientflag = 0, unsigned int port = 0, const char *unix_socket = nullptr)
+ {
+ if (m_mysql == nullptr)
+ m_mysql = mysql_init(nullptr);
+
+ mysql_options(m_mysql, MYSQL_OPT_NONBLOCK, 0);
+
+ MYSQL *ret = nullptr;
+ int status = mysql_real_connect_start(&ret, m_mysql, host, user, passwd, db, port, unix_socket, clientflag);
+ bind(ev);
if (status)
- wait_free_result(status, handler);
+ wait_connect(status, std::forward<OpenHandler>(handler));
else
- handler(mysql::error());
- });
- }
+ handler((ret == nullptr) ? mysql::error(*this) : mysql::error());
+ }
- template<typename Handler>
- void wait_next_result(int status, Handler&& handler)
- {
- m_event->set_io_handler(event_flags(status), mysql_get_timeout_value(m_stmt->mysql),
- [this, handler](int flags) mutable {
- int ret = 0;
- int status = mysql_stmt_next_result_cont(&ret, m_stmt, mysql_status(flags));
- if (status)
- wait_next_result(status, handler);
- else if (ret)
- handler(mysql::error(*this));
- else if (mysql_stmt_field_count(m_stmt) > 0)
- handler(mysql::error());
- else
- next_result(std::forward<Handler>(handler));
- });
- }
-
-};
-
-class async_connection : public basic_database, public qtl::async_connection<async_connection, async_statement>
-{
-public:
- async_connection() = default;
-
- /*
- OpenHandler defines as:
- void handler(const qtl::mysql::error& e) NOEXCEPT;
- */
- template<typename EventLoop, typename OpenHandler>
- void open(EventLoop& ev, OpenHandler&& handler, const char *host, const char *user, const char *passwd, const char *db,
- unsigned long clientflag = 0, unsigned int port = 0, const char *unix_socket = nullptr)
- {
- if (m_mysql == nullptr)
- m_mysql = mysql_init(nullptr);
-
- mysql_options(m_mysql, MYSQL_OPT_NONBLOCK, 0);
-
- MYSQL* ret = nullptr;
- int status = mysql_real_connect_start(&ret, m_mysql, host, user, passwd, db, port, unix_socket, clientflag);
- bind(ev);
- if (status)
- wait_connect(status, std::forward<OpenHandler>(handler));
- else
- handler((ret == nullptr) ? mysql::error(*this) : mysql::error());
- }
-
- /*
- CloseHandler defines as:
- void handler() NOEXCEPT;
- */
- template<typename CloseHandler >
- void close(CloseHandler&& handler) NOEXCEPT
- {
- int status = mysql_close_start(m_mysql);
- if (status)
- {
- wait_close(status, [this, handler]() mutable {
+ /*
+ CloseHandler defines as:
+ void handler() NOEXCEPT;
+ */
+ template <typename CloseHandler>
+ void close(CloseHandler &&handler) NOEXCEPT
+ {
+ int status = mysql_close_start(m_mysql);
+ if (status)
+ {
+ wait_close(status, [this, handler]() mutable
+ {
handler();
- m_mysql = nullptr;
- });
- }
- else
- {
- handler();
- m_mysql = nullptr;
- }
- }
+ m_mysql = nullptr; });
+ }
+ else
+ {
+ handler();
+ m_mysql = nullptr;
+ }
+ }
- /*
- Handler defines as:
- void handler(const qtl::mysql::error& e) NOEXCEPT;
- */
- template<typename Handler>
- void refresh(Handler&& handler, unsigned int options) NOEXCEPT
- {
- int ret = 0;
- int status = mysql_refresh_start(&ret, m_mysql, options);
- if (status)
- wait_operation(status, &mysql_refresh_cont, std::forward<Handler>(handler));
- else
- handler((ret) ? mysql::error(*this) : mysql::error());
- }
+ /*
+ Handler defines as:
+ void handler(const qtl::mysql::error& e) NOEXCEPT;
+ */
+ template <typename Handler>
+ void refresh(Handler &&handler, unsigned int options) NOEXCEPT
+ {
+ int ret = 0;
+ int status = mysql_refresh_start(&ret, m_mysql, options);
+ if (status)
+ wait_operation(status, &mysql_refresh_cont, std::forward<Handler>(handler));
+ else
+ handler((ret) ? mysql::error(*this) : mysql::error());
+ }
- template<typename Handler>
- void select(Handler&& handler, const char* db) NOEXCEPT
- {
- int ret = 0;
- int status = mysql_select_db_start(&ret, m_mysql, db);
- if (status)
- wait_operation(status, &mysql_select_db_cont, std::forward<Handler>(handler));
- else
- handler((ret) ? mysql::error(*this) : mysql::error());
- }
+ template <typename Handler>
+ void select(Handler &&handler, const char *db) NOEXCEPT
+ {
+ int ret = 0;
+ int status = mysql_select_db_start(&ret, m_mysql, db);
+ if (status)
+ wait_operation(status, &mysql_select_db_cont, std::forward<Handler>(handler));
+ else
+ handler((ret) ? mysql::error(*this) : mysql::error());
+ }
- template<typename Handler>
- void is_alive(Handler&& handler) NOEXCEPT
- {
- int ret = 0;
- int status = mysql_ping_start(&ret, m_mysql);
- if (status)
- wait_operation(status, &mysql_ping_cont, std::forward<Handler>(handler));
- else
- handler((ret) ? mysql::error(*this) : mysql::error());
- }
+ template <typename Handler>
+ void is_alive(Handler &&handler) NOEXCEPT
+ {
+ int ret = 0;
+ int status = mysql_ping_start(&ret, m_mysql);
+ if (status)
+ wait_operation(status, &mysql_ping_cont, std::forward<Handler>(handler));
+ else
+ handler((ret) ? mysql::error(*this) : mysql::error());
+ }
- /*
- Handler defines as:
- void handler(const qtl::mysql::error& e, uint64_t affected) NOEXCEPT;
- */
- template<typename ExecuteHandler>
- void simple_execute(ExecuteHandler&& handler, const char* query_text) NOEXCEPT
- {
- int ret = 0;
- int status = mysql_query_start(&ret, m_mysql, query_text);
- if (status)
- {
- wait_operation(status, &mysql_query_cont, [this, handler](const mysql::error& e) {
+ /*
+ Handler defines as:
+ void handler(const qtl::mysql::error& e, uint64_t affected) NOEXCEPT;
+ */
+ template <typename ExecuteHandler>
+ void simple_execute(ExecuteHandler &&handler, const char *query_text) NOEXCEPT
+ {
+ int ret = 0;
+ int status = mysql_query_start(&ret, m_mysql, query_text);
+ if (status)
+ {
+ wait_operation(status, &mysql_query_cont, [this, handler](const mysql::error &e)
+ {
uint64_t affected = 0;
if (!e) affected = affected_rows();
- handler(e, affected);
- });
- }
- else
- {
- uint64_t affected = 0;
- if (ret >= 0) affected = affected_rows();
- handler((ret) ? mysql::error(*this) : mysql::error(), affected);
- }
- }
+ handler(e, affected); });
+ }
+ else
+ {
+ uint64_t affected = 0;
+ if (ret >= 0)
+ affected = affected_rows();
+ handler((ret) ? mysql::error(*this) : mysql::error(), affected);
+ }
+ }
- template<typename ExecuteHandler>
- void simple_execute(ExecuteHandler&& handler, const char* query_text, unsigned long text_length) NOEXCEPT
- {
- int ret = 0;
- int status = mysql_real_query_start(&ret, m_mysql, query_text, text_length);
- if (status)
- {
- wait_operation(status, &mysql_real_query_cont, [this, handler](const mysql::error& e) mutable {
+ template <typename ExecuteHandler>
+ void simple_execute(ExecuteHandler &&handler, const char *query_text, unsigned long text_length) NOEXCEPT
+ {
+ int ret = 0;
+ int status = mysql_real_query_start(&ret, m_mysql, query_text, text_length);
+ if (status)
+ {
+ wait_operation(status, &mysql_real_query_cont, [this, handler](const mysql::error &e) mutable
+ {
uint64_t affected = 0;
if (!e) affected = affected_rows();
- handler(e, affected);
- });
- }
- else
- {
- uint64_t affected = 0;
- if (ret >= 0) affected = affected_rows();
- handler((ret) ? mysql::error(*this) : mysql::error(), affected);
- }
- }
+ handler(e, affected); });
+ }
+ else
+ {
+ uint64_t affected = 0;
+ if (ret >= 0)
+ affected = affected_rows();
+ handler((ret) ? mysql::error(*this) : mysql::error(), affected);
+ }
+ }
- template<typename Handler>
- void auto_commit(Handler&& handler, bool on) NOEXCEPT
- {
- my_bool ret;
- int status = mysql_autocommit_start(&ret, m_mysql, on ? 1 : 0);
- if(status)
- wait_operation(status, &mysql_autocommit_cont, std::forward<Handler>(handler));
- else
- handler((ret) ? mysql::error(*this) : mysql::error());
- }
+ template <typename Handler>
+ void auto_commit(Handler &&handler, bool on) NOEXCEPT
+ {
+ my_bool ret;
+ int status = mysql_autocommit_start(&ret, m_mysql, on ? 1 : 0);
+ if (status)
+ wait_operation(status, &mysql_autocommit_cont, std::forward<Handler>(handler));
+ else
+ handler((ret) ? mysql::error(*this) : mysql::error());
+ }
- template<typename Handler>
- void begin_transaction(Handler&& handler) NOEXCEPT
- {
- auto_commit(handler, false);
- }
+ template <typename Handler>
+ void begin_transaction(Handler &&handler) NOEXCEPT
+ {
+ auto_commit(handler, false);
+ }
- template<typename Handler>
- void rollback(Handler&& handler) NOEXCEPT
- {
- my_bool ret;
- int status = mysql_rollback_start(&ret, m_mysql);
- if (status)
- wait_operation(status, &mysql_rollback_cont, std::forward<Handler>(handler));
- else
- handler((ret) ? mysql::error(*this) : mysql::error());
- }
+ template <typename Handler>
+ void rollback(Handler &&handler) NOEXCEPT
+ {
+ my_bool ret;
+ int status = mysql_rollback_start(&ret, m_mysql);
+ if (status)
+ wait_operation(status, &mysql_rollback_cont, std::forward<Handler>(handler));
+ else
+ handler((ret) ? mysql::error(*this) : mysql::error());
+ }
- template<typename Handler>
- void commit(Handler&& handler) NOEXCEPT
- {
- my_bool ret;
- int status = mysql_commit_start(&ret, m_mysql);
- if (status)
- wait_operation(status, &mysql_commit_cont, std::forward<Handler>(handler));
- else
- handler((ret) ? mysql::error(*this) : mysql::error());
- }
+ template <typename Handler>
+ void commit(Handler &&handler) NOEXCEPT
+ {
+ my_bool ret;
+ int status = mysql_commit_start(&ret, m_mysql);
+ if (status)
+ wait_operation(status, &mysql_commit_cont, std::forward<Handler>(handler));
+ else
+ handler((ret) ? mysql::error(*this) : mysql::error());
+ }
- /*
- RowHandler defines as:
- bool row_handler(MYSQL_ROW row, int field_count) NOEXCEPT;
- ResultHandler defines as:
- void result_handler(const qtl::mysql::error& e, size_t row_count) NOEXCEPT;
- */
- template<typename RowHandler, typename ResultHandler>
- void simple_query(const char* query, unsigned long length, RowHandler&& row_handler, ResultHandler&& result_handler) NOEXCEPT
- {
- simple_execute([this, row_handler, result_handler](const mysql::error& e, uint64_t affected) mutable {
+ /*
+ RowHandler defines as:
+ bool row_handler(MYSQL_ROW row, int field_count) NOEXCEPT;
+ ResultHandler defines as:
+ void result_handler(const qtl::mysql::error& e, size_t row_count) NOEXCEPT;
+ */
+ template <typename RowHandler, typename ResultHandler>
+ void simple_query(const char *query, unsigned long length, RowHandler &&row_handler, ResultHandler &&result_handler) NOEXCEPT
+ {
+ simple_execute([this, row_handler, result_handler](const mysql::error &e, uint64_t affected) mutable
+ {
if (e)
{
result_handler(e, 0);
@@ -1755,180 +1793,185 @@
else
{
result_handler(mysql::error(), 0);
+ } }, query, length);
}
- }, query, length);
+
+ template <typename Handler>
+ void open_command(const char *query_text, size_t text_length, Handler &&handler)
+ {
+ std::shared_ptr<async_statement> stmt = std::make_shared<async_statement>(*this);
+ stmt->open([stmt, handler](const mysql::error &e) mutable
+ { handler(e, stmt); }, query_text, (unsigned long)text_length);
+ }
+
+ socket_type socket() const NOEXCEPT { return mysql_get_socket(m_mysql); }
+
+ private:
+ template <typename OpenHandler>
+ void wait_connect(int status, OpenHandler &&handler) NOEXCEPT
+ {
+ m_event_handler->set_io_handler(event_flags(status), mysql_get_timeout_value(m_mysql),
+ [this, handler](int flags) mutable
+ {
+ MYSQL *ret = nullptr;
+ int status = mysql_real_connect_cont(&ret, m_mysql, mysql_status(flags));
+ if (status)
+ wait_connect(status, handler);
+ else
+ handler((ret == nullptr) ? mysql::error(*this) : mysql::error());
+ });
+ }
+
+ template <typename CloseHandler>
+ void wait_close(int status, CloseHandler &&handler) NOEXCEPT
+ {
+ m_event_handler->set_io_handler(event_flags(status), mysql_get_timeout_value(m_mysql),
+ [this, handler](int flags) mutable
+ {
+ MYSQL *ret = nullptr;
+ int status = mysql_close_cont(m_mysql, mysql_status(flags));
+ if (status)
+ wait_close(status, handler);
+ else
+ handler();
+ });
+ }
+
+ template <typename Func, typename Handler>
+ void wait_operation(int status, Func func, Handler &&handler) NOEXCEPT
+ {
+ m_event_handler->set_io_handler(event_flags(status), mysql_get_timeout_value(m_mysql),
+ [this, func, handler](int flags) mutable
+ {
+ int ret = 0;
+ int status = func(&ret, m_mysql, mysql_status(flags));
+ if (status)
+ wait_operation(status, func, handler);
+ else
+ handler((ret) ? mysql::error(*this) : mysql::error());
+ });
+ }
+
+ template <typename RowHandler, typename ResultHandler>
+ void wait_query(int status, int field_count, RowHandler &&row_handler, ResultHandler &&result_handler) NOEXCEPT
+ {
+ m_event_handler->set_io_handler(event_flags(status), mysql_get_timeout_value(m_mysql),
+ [this, field_count, row_handler, result_handler](int flags) mutable
+ {
+ MYSQL_RES *result = 0;
+ int status = mysql_store_result_cont(&result, m_mysql, mysql_status(flags));
+ if (status)
+ wait_query(status, field_count, row_handler, result_handler);
+ else if (result)
+ fetch_rows(result, field_count, 0, row_handler, result_handler);
+ else
+ result_handler(mysql::error(*this), 0);
+ });
+ }
+
+ template <typename RowHandler, typename ResultHandler>
+ void fetch_rows(MYSQL_RES *result, int field_count, size_t row_count, RowHandler &&row_handler, ResultHandler &&result_handler) NOEXCEPT
+ {
+ MYSQL_ROW row;
+ int status = mysql_fetch_row_start(&row, result);
+ if (status)
+ wait_fetch(status, result, field_count, row_count, row_handler, result_handler);
+ else if (row && row_handler(row, field_count))
+ fetch_rows(result, field_count, row_count + 1, row_handler, result_handler);
+ else
+ free_result(result, row_count, result_handler);
+ }
+
+ template <typename ResultHandler>
+ void free_result(MYSQL_RES *result, size_t row_count, ResultHandler &&result_handler) NOEXCEPT
+ {
+ int status = mysql_free_result_start(result);
+ if (status)
+ wait_free_result(status, result, row_count, result_handler);
+ else
+ result_handler(mysql::error(), row_count);
+ }
+
+ template <typename RowHandler, typename ResultHandler>
+ void wait_fetch(int status, MYSQL_RES *result, int field_count, size_t row_count, RowHandler &&row_handler, ResultHandler &&result_handler)
+ {
+ m_event_handler->set_io_handler(event_flags(status), mysql_get_timeout_value(m_mysql),
+ [this, result, field_count, row_count, row_handler, result_handler](int flags) mutable
+ {
+ MYSQL_ROW row;
+ int status = mysql_fetch_row_cont(&row, result, mysql_status(flags));
+ if (status)
+ wait_fetch(status, result, field_count, row_count, row_handler, result_handler);
+ else if (result && row_handler(row, field_count))
+ fetch_rows(result, field_count, row_count + 1, row_handler, result_handler);
+ else
+ free_result(result, row_count, result_handler);
+ });
+ }
+
+ template <typename ResultHandler>
+ void wait_free_result(int status, MYSQL_RES *result, size_t row_count, ResultHandler &&handler) NOEXCEPT
+ {
+ m_event_handler->set_io_handler(event_flags(status), mysql_get_timeout_value(m_mysql),
+ [this, result, row_count, handler](int flags) mutable
+ {
+ MYSQL *ret = nullptr;
+ int status = mysql_free_result_cont(result, mysql_status(flags));
+ if (status)
+ wait_free_result(status, result, row_count, handler);
+ else
+ handler(mysql::error(), row_count);
+ });
+ }
+ };
+
+ inline async_statement::async_statement(async_connection &db)
+ : base_statement(static_cast<basic_database &>(db))
+ {
+ m_event = db.event();
+ }
+
+#endif // MariaDB 10.0
+
+ typedef qtl::transaction<database> transaction;
+
+ template <typename Record>
+ using query_iterator = qtl::query_iterator<statement, Record>;
+
+ template <typename Record>
+ using query_result = qtl::query_result<statement, Record>;
+
+ template <typename Params>
+ inline statement &operator<<(statement &stmt, const Params ¶ms)
+ {
+ stmt.reset();
+ stmt.execute(params);
+ return stmt;
+ }
+
+ inline error::error(const base_statement &stmt)
+ {
+ const char *errmsg = stmt.errmsg();
+ m_error = stmt.error();
+ if (errmsg)
+ m_errmsg = errmsg;
+ }
+
+ inline error::error(const basic_database &db)
+ {
+ const char *errmsg = db.errmsg();
+ m_error = db.error();
+ if (errmsg)
+ m_errmsg = errmsg;
+ }
+
+ inline base_statement::base_statement(basic_database &db)
+ {
+ m_stmt = mysql_stmt_init(db.handle());
+ m_result = nullptr;
+ }
+
}
-
- template<typename Handler>
- void open_command(const char* query_text, size_t text_length, Handler&& handler)
- {
- std::shared_ptr<async_statement> stmt=std::make_shared<async_statement>(*this);
- stmt->open([stmt, handler](const mysql::error& e) mutable {
- handler(e, stmt);
- }, query_text, (unsigned long)text_length);
- }
-
- socket_type socket() const NOEXCEPT { return mysql_get_socket(m_mysql); }
-
-private:
- template<typename OpenHandler>
- void wait_connect(int status, OpenHandler&& handler) NOEXCEPT
- {
- m_event_handler->set_io_handler(event_flags(status), mysql_get_timeout_value(m_mysql),
- [this, handler](int flags) mutable {
- MYSQL* ret = nullptr;
- int status = mysql_real_connect_cont(&ret, m_mysql, mysql_status(flags));
- if (status)
- wait_connect(status, handler);
- else
- handler((ret == nullptr) ? mysql::error(*this) : mysql::error());
- });
- }
-
- template<typename CloseHandler>
- void wait_close(int status, CloseHandler&& handler) NOEXCEPT
- {
- m_event_handler->set_io_handler(event_flags(status), mysql_get_timeout_value(m_mysql),
- [this, handler](int flags) mutable {
- MYSQL* ret = nullptr;
- int status = mysql_close_cont(m_mysql, mysql_status(flags));
- if (status)
- wait_close(status, handler);
- else
- handler();
- });
- }
-
- template<typename Func, typename Handler>
- void wait_operation(int status, Func func, Handler&& handler) NOEXCEPT
- {
- m_event_handler->set_io_handler(event_flags(status), mysql_get_timeout_value(m_mysql),
- [this, func, handler](int flags) mutable {
- int ret = 0;
- int status = func(&ret, m_mysql, mysql_status(flags));
- if (status)
- wait_operation(status, func, handler);
- else
- handler((ret) ? mysql::error(*this) : mysql::error());
- });
- }
-
- template<typename RowHandler, typename ResultHandler>
- void wait_query(int status, int field_count, RowHandler&& row_handler, ResultHandler&& result_handler) NOEXCEPT
- {
- m_event_handler->set_io_handler(event_flags(status), mysql_get_timeout_value(m_mysql),
- [this, field_count, row_handler, result_handler](int flags) mutable {
- MYSQL_RES* result = 0;
- int status = mysql_store_result_cont(&result, m_mysql, mysql_status(flags));
- if (status)
- wait_query(status, field_count, row_handler, result_handler);
- else if (result)
- fetch_rows(result, field_count, 0, row_handler, result_handler);
- else
- result_handler(mysql::error(*this), 0);
- });
- }
-
- template<typename RowHandler, typename ResultHandler>
- void fetch_rows(MYSQL_RES* result, int field_count, size_t row_count, RowHandler&& row_handler, ResultHandler&& result_handler) NOEXCEPT
- {
- MYSQL_ROW row;
- int status = mysql_fetch_row_start(&row, result);
- if (status)
- wait_fetch(status, result, field_count, row_count, row_handler, result_handler);
- else if(row && row_handler(row, field_count))
- fetch_rows(result, field_count, row_count + 1, row_handler, result_handler);
- else
- free_result(result, row_count, result_handler);
- }
-
- template<typename ResultHandler>
- void free_result(MYSQL_RES* result, size_t row_count, ResultHandler&& result_handler) NOEXCEPT
- {
- int status = mysql_free_result_start(result);
- if (status)
- wait_free_result(status, result, row_count, result_handler);
- else
- result_handler(mysql::error(), row_count);
- }
-
- template<typename RowHandler, typename ResultHandler>
- void wait_fetch(int status, MYSQL_RES* result, int field_count, size_t row_count, RowHandler&& row_handler, ResultHandler&& result_handler)
- {
- m_event_handler->set_io_handler(event_flags(status), mysql_get_timeout_value(m_mysql),
- [this, result, field_count, row_count, row_handler, result_handler](int flags) mutable {
- MYSQL_ROW row;
- int status = mysql_fetch_row_cont(&row, result, mysql_status(flags));
- if (status)
- wait_fetch(status, result, field_count, row_count, row_handler, result_handler);
- else if (result && row_handler(row, field_count))
- fetch_rows(result, field_count, row_count+1, row_handler, result_handler);
- else
- free_result(result, row_count, result_handler);
- });
- }
-
- template<typename ResultHandler>
- void wait_free_result(int status, MYSQL_RES* result, size_t row_count, ResultHandler&& handler) NOEXCEPT
- {
- m_event_handler->set_io_handler(event_flags(status), mysql_get_timeout_value(m_mysql),
- [this, result, row_count, handler](int flags) mutable {
- MYSQL* ret = nullptr;
- int status = mysql_free_result_cont(result, mysql_status(flags));
- if (status)
- wait_free_result(status, result, row_count, handler);
- else
- handler(mysql::error(), row_count);
- });
- }
-
-};
-
-inline async_statement::async_statement(async_connection& db)
-: base_statement(static_cast<basic_database&>(db))
-{
- m_event=db.event();
-}
-
-#endif //MariaDB 10.0
-
-typedef qtl::transaction<database> transaction;
-
-template<typename Record>
-using query_iterator = qtl::query_iterator<statement, Record>;
-
-template<typename Record>
-using query_result = qtl::query_result<statement, Record>;
-
-template<typename Params>
-inline statement& operator<<(statement& stmt, const Params& params)
-{
- stmt.reset();
- stmt.execute(params);
- return stmt;
-}
-
-inline error::error(const base_statement& stmt)
-{
- const char* errmsg=stmt.errmsg();
- m_error=stmt.error();
- if(errmsg) m_errmsg=errmsg;
-}
-
-inline error::error(const basic_database& db)
-{
- const char* errmsg=db.errmsg();
- m_error=db.error();
- if(errmsg) m_errmsg=errmsg;
-}
-
-inline base_statement::base_statement(basic_database& db)
-{
- m_stmt=mysql_stmt_init(db.handle());
- m_result=nullptr;
-}
-
-}
}
diff --git a/include/qtl_mysql_pool.hpp b/include/qtl_mysql_pool.hpp
index 9dc8948..d0f0cd1 100644
--- a/include/qtl_mysql_pool.hpp
+++ b/include/qtl_mysql_pool.hpp
@@ -7,52 +7,54 @@
namespace qtl
{
-namespace mysql
-{
-
-class database_pool : public qtl::database_pool<database>
-{
-public:
- database_pool() : m_port(0) { }
- virtual ~database_pool() { }
- virtual database* new_database() throw() override
+ namespace mysql
{
- database* db=new database;
- if(!db->open(m_host.data(), m_user.data(), m_password.data(), m_database.data(), 0, m_port))
- {
- delete db;
- db=NULL;
- }
- else
- {
- db->charset_name("utf8");
- }
- return db;
- }
-protected:
- std::string m_host;
- unsigned short m_port;
- std::string m_database;
- std::string m_user;
- std::string m_password;
-};
+ class database_pool : public qtl::database_pool<database>
+ {
+ public:
+ database_pool() : m_port(0) {}
+ virtual ~database_pool() {}
+ virtual database *new_database() throw() override
+ {
+ database *db = new database;
+ if (!db->open(m_host.data(), m_user.data(), m_password.data(), m_database.data(), 0, m_port))
+ {
+ delete db;
+ db = NULL;
+ }
+ else
+ {
+ db->charset_name("utf8");
+ }
+ return db;
+ }
+
+ protected:
+ std::string m_host;
+ unsigned short m_port;
+ std::string m_database;
+ std::string m_user;
+ std::string m_password;
+ };
#if MARIADB_VERSION_ID >= 050500
-template<typename EventLoop>
-class async_pool : public qtl::async_pool<async_pool<EventLoop>, EventLoop, async_connection>
-{
- typedef qtl::async_pool<async_pool<EventLoop>, EventLoop, async_connection> base_class;
-public:
- async_pool(EventLoop& ev) : base_class(ev), m_port(0) { }
- virtual ~async_pool() { }
+ template <typename EventLoop>
+ class async_pool : public qtl::async_pool<async_pool<EventLoop>, EventLoop, async_connection>
+ {
+ typedef qtl::async_pool<async_pool<EventLoop>, EventLoop, async_connection> base_class;
- template<typename Handler>
- void new_connection(EventLoop& ev, Handler&& handler) throw()
- {
- async_connection* db = new async_connection;
- db->open(ev, [this, handler, db](const mysql::error& e) mutable {
+ public:
+ async_pool(EventLoop &ev) : base_class(ev), m_port(0) {}
+ virtual ~async_pool() {}
+
+ template <typename Handler>
+ void new_connection(EventLoop &ev, Handler &&handler) throw()
+ {
+ async_connection *db = new async_connection;
+ db->open(ev, [this, handler, db](const mysql::error &e) mutable
+ {
if (e)
{
delete db;
@@ -62,21 +64,20 @@
{
db->charset_name("utf8");
}
- handler(e, db);
- }, m_host.data(), m_user.data(), m_password.data(), m_database.data(), 0, m_port);
+ handler(e, db); }, m_host.data(), m_user.data(), m_password.data(), m_database.data(), 0, m_port);
+ }
+
+ protected:
+ std::string m_host;
+ unsigned short m_port;
+ std::string m_database;
+ std::string m_user;
+ std::string m_password;
+ };
+
+#endif // MariaDB
+
}
-
-protected:
- std::string m_host;
- unsigned short m_port;
- std::string m_database;
- std::string m_user;
- std::string m_password;
-};
-
-#endif //MariaDB
-
-}
}
diff --git a/include/qtl_odbc.hpp b/include/qtl_odbc.hpp
index 3233ead..5de6fcd 100644
--- a/include/qtl_odbc.hpp
+++ b/include/qtl_odbc.hpp
@@ -18,8 +18,7 @@
#if (ODBCVER >= 0x0380) && (_WIN32_WINNT >= 0x0602)
#define QTL_ODBC_ENABLE_ASYNC_MODE 1
-#endif //ODBC 3.80 && Windows
-
+#endif // ODBC 3.80 && Windows
#include "qtl_common.hpp"
#include "qtl_async.hpp"
@@ -27,1343 +26,1365 @@
namespace qtl
{
-namespace odbc
-{
+ namespace odbc
+ {
-template<SQLSMALLINT> class object;
-class base_database;
+ template <SQLSMALLINT>
+ class object;
+ class base_database;
-class error : public std::exception
-{
-public:
- error() : m_errno(SQL_SUCCESS) { }
- template<SQLSMALLINT Type>
- error(const object<Type>& h, SQLINTEGER code);
- error(SQLINTEGER code, const char* msg) : m_errno(code), m_errmsg(msg) { }
- SQLINTEGER code() const { return m_errno; }
- operator bool() const { return m_errno!=SQL_SUCCESS && m_errno!=SQL_SUCCESS_WITH_INFO; }
- virtual const char* what() const throw() override { return m_errmsg.data(); }
-private:
- SQLINTEGER m_errno;
- std::string m_errmsg;
-};
-
-template<SQLSMALLINT Type>
-class object
-{
-public:
- enum { handler_type=Type };
- object() : m_handle(SQL_NULL_HANDLE) { };
- object(const object&) = delete;
- object(object&& src) : m_handle(src.m_handle)
- {
- src.m_handle=SQL_NULL_HANDLE;
- }
- explicit object(SQLHANDLE parent)
- {
- verify_error(SQLAllocHandle(handler_type, parent, &m_handle));
- }
- ~object()
- {
- close();
- }
- object& operator=(const object&) = delete;
- object& operator=(object&& src)
- {
- if(this!=&src)
+ class error : public std::exception
{
- close();
- m_handle=src.m_handle;
- src.m_handle=NULL;
- }
- return *this;
- }
- SQLHANDLE handle() const { return m_handle; }
+ public:
+ error() : m_errno(SQL_SUCCESS) {}
+ template <SQLSMALLINT Type>
+ error(const object<Type> &h, SQLINTEGER code);
+ error(SQLINTEGER code, const char *msg) : m_errno(code), m_errmsg(msg) {}
+ SQLINTEGER code() const { return m_errno; }
+ operator bool() const { return m_errno != SQL_SUCCESS && m_errno != SQL_SUCCESS_WITH_INFO; }
+ virtual const char *what() const throw() override { return m_errmsg.data(); }
- void close()
- {
- if(m_handle)
+ private:
+ SQLINTEGER m_errno;
+ std::string m_errmsg;
+ };
+
+ template <SQLSMALLINT Type>
+ class object
{
- verify_error(SQLFreeHandle(handler_type, m_handle));
- m_handle=SQL_NULL_HANDLE;
- }
- }
-
- void verify_error(SQLINTEGER code) const
- {
- if (code < 0)
- throw odbc::error(*this, code);
- }
-
-protected:
- SQLHANDLE m_handle;
-};
-
-class blobbuf : public qtl::blobbuf
-{
-public:
- blobbuf() : m_stmt(nullptr), m_field(0)
- {
- }
- blobbuf(const blobbuf&) = default;
- blobbuf& operator=(const blobbuf&) = default;
- virtual ~blobbuf() { overflow(); }
-
- void open(object<SQL_HANDLE_STMT>* stmt, SQLSMALLINT field, std::ios_base::openmode mode)
- {
- if (m_stmt && m_field)
- {
- overflow();
- }
-
- assert(stmt != SQL_NULL_HANDLE);
- m_stmt = stmt;
- m_field = field;
- m_size = INTMAX_MAX;
- init_buffer(mode);
- }
-
-private:
- object<SQL_HANDLE_STMT>* m_stmt;
- SQLSMALLINT m_field;
-
-protected:
- virtual bool read_blob(char* buffer, off_type& count, pos_type position) override
- {
- SQLLEN indicator=0;
- SQLRETURN ret = SQLGetData(m_stmt->handle(), m_field + 1, SQL_C_BINARY, buffer, static_cast<SQLINTEGER>(count), const_cast<SQLLEN*>(&indicator));
- if (ret != SQL_NO_DATA)
- {
- count = (indicator > count) || (indicator == SQL_NO_TOTAL) ?
- count : indicator;
- m_stmt->verify_error(ret);
- return true;
- }
- else return false;
- }
-
- virtual void write_blob(const char* buffer, size_t count) override
- {
- m_stmt->verify_error(SQLPutData(m_stmt->handle(), (SQLPOINTER)buffer, count));
- }
-};
-
-class environment final : public object<SQL_HANDLE_ENV>
-{
-public:
- environment() : object(SQL_NULL_HANDLE)
- {
-#if ODBCVER >= 0x0380
- const SQLPOINTER version = (SQLPOINTER)SQL_OV_ODBC3_80;
-#else
- const SQLPOINTER version = (SQLPOINTER)SQL_OV_ODBC3;
-#endif
- verify_error(SQLSetEnvAttr(m_handle, SQL_ATTR_ODBC_VERSION, version, SQL_IS_INTEGER));
- }
- environment(environment&& src) : object(std::forward<environment>(src)) { }
-
- int32_t version() const
- {
- int32_t ver = 0;
- verify_error(SQLGetEnvAttr(m_handle, SQL_ATTR_ODBC_VERSION, &ver, sizeof(DWORD), NULL));
- return ver;
- }
-};
-
-class base_statement : public object<SQL_HANDLE_STMT>
-{
-public:
- explicit base_statement(base_database& db);
- base_statement(base_statement&& src)
- : object(std::forward<base_statement>(src)), m_params(std::forward<std::vector<param_data>>(src.m_params))
- {
- m_binded_cols=src.m_binded_cols;
- src.m_binded_cols=false;
- m_blob_buffer=src.m_blob_buffer;
- src.m_blob_buffer=NULL;
- }
- ~base_statement()
- {
- if(m_blob_buffer)
- free(m_blob_buffer);
- }
- base_statement& operator=(base_statement&& src)
- {
- if(this!=&src)
- {
- object::operator =(std::forward<base_statement>(src));
- m_params=std::forward<std::vector<param_data>>(src.m_params);
- m_binded_cols=src.m_binded_cols;
- src.m_binded_cols=false;
- m_blob_buffer=src.m_blob_buffer;
- src.m_blob_buffer=NULL;
- }
- return *this;
- }
-
- void bind_param(size_t index, const std::nullptr_t&)
- {
- m_params[index].m_indicator=SQL_NULL_DATA;
- verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index+1),
- SQL_PARAM_INPUT, SQL_C_DEFAULT, SQL_DEFAULT, 0, 0, NULL, 0, &m_params[index].m_indicator));
- }
- void bind_param(size_t index, const qtl::null&)
- {
- bind_param(index, nullptr);
- }
- void bind_param(size_t index, const int8_t& v)
- {
- verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_PARAM_INPUT, SQL_C_STINYINT, SQL_TINYINT,
- 0, 0, (SQLPOINTER)&v, 0, NULL));
- }
- void bind_param(size_t index, const uint8_t& v)
- {
- verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_PARAM_INPUT, SQL_C_UTINYINT, SQL_TINYINT,
- 0, 0, (SQLPOINTER)&v, 0, NULL));
- }
- void bind_param(size_t index, const int16_t& v)
- {
- verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_PARAM_INPUT, SQL_C_SSHORT, SQL_SMALLINT,
- 0, 0, (SQLPOINTER)&v, 0, NULL));
- }
- void bind_param(size_t index, const uint16_t& v)
- {
- verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_PARAM_INPUT, SQL_C_USHORT, SQL_SMALLINT,
- 0, 0, (SQLPOINTER)&v, 0, NULL));
- }
- void bind_param(size_t index, const int32_t& v)
- {
- verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER,
- 0, 0, (SQLPOINTER)&v, 0, NULL));
- }
- void bind_param(size_t index, const uint32_t& v)
- {
- verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER,
- 0, 0, (SQLPOINTER)&v, 0, NULL));
- }
- void bind_param(size_t index, const int64_t& v)
- {
- verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_PARAM_INPUT, SQL_C_SBIGINT, SQL_BIGINT,
- 0, 0, (SQLPOINTER)&v, 0, NULL));
- }
- void bind_param(size_t index, const uint64_t& v)
- {
- verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_PARAM_INPUT, SQL_C_UBIGINT, SQL_BIGINT,
- 0, 0, (SQLPOINTER)&v, 0, NULL));
- }
- void bind_param(size_t index, const double& v)
- {
- verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DOUBLE,
- 0, 0, (SQLPOINTER)&v, 0, NULL));
- }
- void bind_param(size_t index, const float& v)
- {
- verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_PARAM_INPUT, SQL_C_FLOAT, SQL_FLOAT,
- 0, 0, (SQLPOINTER)&v, 0, NULL));
- }
- void bind_param(size_t index, const bool& v)
- {
- verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_PARAM_INPUT, SQL_C_BIT, SQL_BIT,
- 0, 0, (SQLPOINTER)&v, 0, NULL));
- }
- void bind_param(size_t index, const DATE_STRUCT& v)
- {
- verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_PARAM_INPUT, SQL_C_DATE, SQL_DATE,
- 0, 0, (SQLPOINTER)&v, 0, NULL));
- }
- void bind_param(size_t index, const TIME_STRUCT& v)
- {
- verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_PARAM_INPUT, SQL_C_TIME, SQL_TIME,
- 0, 0, (SQLPOINTER)&v, 0, NULL));
- }
- void bind_param(size_t index, const TIMESTAMP_STRUCT& v)
- {
- verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_PARAM_INPUT, SQL_C_TIMESTAMP, SQL_TIMESTAMP,
- 0, 0, (SQLPOINTER)&v, 0, NULL));
- }
- void bind_param(size_t index, const SQLGUID& v)
- {
- verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_PARAM_INPUT, SQL_C_GUID, SQL_GUID,
- 0, 0, (SQLPOINTER)&v, 0, NULL));
- }
- void bind_param(size_t index, const SQL_NUMERIC_STRUCT& v)
- {
- verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_PARAM_INPUT, SQL_C_NUMERIC, SQL_NUMERIC,
- 0, 0, (SQLPOINTER)&v, 0, NULL));
- }
- void bind_param(size_t index, const char* v, size_t n=SQL_NTS, SQLULEN size=0)
- {
- m_params[index].m_indicator=n;
- if(size==0) size=strlen(v);
- verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR,
- size, 0, (SQLPOINTER)v, 0, &m_params[index].m_indicator));
- }
- void bind_param(size_t index, const wchar_t* v, size_t n=SQL_NTS, SQLULEN size=0)
- {
- m_params[index].m_indicator=n;
- if(size==0) size=wcslen(v);
- verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_PARAM_INPUT, SQL_C_WCHAR, SQL_WCHAR,
- size, 0, (SQLPOINTER)v, 0, &m_params[index].m_indicator));
- }
- void bind_param(size_t index, const std::string& v)
- {
- bind_param(index, v.data(), v.size(), v.size());
- }
- void bind_param(size_t index, const std::wstring& v)
- {
- bind_param(index, v.data(), v.size(), v.size());
- }
- void bind_param(size_t index, const const_blob_data& v)
- {
- m_params[index].m_indicator=v.size;
- verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_PARAM_INPUT, SQL_C_BINARY, SQL_BINARY,
- v.size, 0, (SQLPOINTER)v.data, 0, &m_params[index].m_indicator));
- }
- void bind_param(size_t index, std::istream& s)
- {
- if(m_blob_buffer==NULL)
- m_blob_buffer=malloc(blob_buffer_size);
- m_params[index].m_data=m_blob_buffer;
- m_params[index].m_size=blob_buffer_size;
- m_params[index].m_indicator=SQL_LEN_DATA_AT_EXEC(m_params[index].m_size);
- verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY,
- INT_MAX, 0, &m_params[index], 0, &m_params[index].m_indicator));
- m_params[index].m_after_fetch=[this, &s](const param_data& p) {
- SQLLEN readed=SQL_NULL_DATA;
- while(!s.eof() && !s.fail())
+ public:
+ enum
{
- s.read((char*)p.m_data, p.m_size);
- readed=(unsigned long)s.gcount();
- if(readed>0)
+ handler_type = Type
+ };
+ object() : m_handle(SQL_NULL_HANDLE){};
+ object(const object &) = delete;
+ object(object &&src) : m_handle(src.m_handle)
+ {
+ src.m_handle = SQL_NULL_HANDLE;
+ }
+ explicit object(SQLHANDLE parent)
+ {
+ verify_error(SQLAllocHandle(handler_type, parent, &m_handle));
+ }
+ ~object()
+ {
+ close();
+ }
+ object &operator=(const object &) = delete;
+ object &operator=(object &&src)
+ {
+ if (this != &src)
{
- verify_error(SQLPutData(m_handle, p.m_data, readed));
+ close();
+ m_handle = src.m_handle;
+ src.m_handle = NULL;
+ }
+ return *this;
+ }
+ SQLHANDLE handle() const { return m_handle; }
+
+ void close()
+ {
+ if (m_handle)
+ {
+ verify_error(SQLFreeHandle(handler_type, m_handle));
+ m_handle = SQL_NULL_HANDLE;
}
}
- };
- }
- void bind_param(size_t index, const blob_writer& param)
- {
- m_params[index].m_data = nullptr;
- m_params[index].m_size = blob_buffer_size;
- m_params[index].m_indicator = SQL_LEN_DATA_AT_EXEC(m_params[index].m_size);
- verify_error(SQLBindParameter(m_handle, static_cast<SQLSMALLINT>(index + 1), SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY,
- INT_MAX, 0, &m_params[index], 0, &m_params[index].m_indicator));
- m_params[index].m_after_fetch = [this, index, ¶m](const param_data& b) {
- blobbuf buf;
- buf.open(this, static_cast<SQLSMALLINT>(index), std::ios::out);
- std::ostream s(&buf);
- param(s);
- };
- }
+ void verify_error(SQLINTEGER code) const
+ {
+ if (code < 0)
+ throw odbc::error(*this, code);
+ }
- void bind_field(size_t index, bool&& v)
- {
- verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_C_BIT, &v, 0, &m_params[index].m_indicator));
- }
- void bind_field(size_t index, int8_t&& v)
- {
- verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_C_STINYINT, &v, 0, &m_params[index].m_indicator));
- }
- void bind_field(size_t index, uint8_t&& v)
- {
- verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_C_UTINYINT, &v, 0, &m_params[index].m_indicator));
- }
- void bind_field(size_t index, int16_t&& v)
- {
- verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_C_SSHORT, &v, 0, &m_params[index].m_indicator));
- }
- void bind_field(size_t index, uint16_t&& v)
- {
- verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_C_USHORT, &v, 0, &m_params[index].m_indicator));
- }
- void bind_field(size_t index, int32_t&& v)
- {
- verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_C_SLONG, &v, 0, &m_params[index].m_indicator));
- }
- void bind_field(size_t index, uint32_t&& v)
- {
- verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_C_ULONG, &v, 0, &m_params[index].m_indicator));
- }
- void bind_field(size_t index, int64_t&& v)
- {
- verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_C_SBIGINT, &v, 0, &m_params[index].m_indicator));
- }
- void bind_field(size_t index, uint64_t&& v)
- {
- verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_C_UBIGINT, &v, 0, &m_params[index].m_indicator));
- }
- void bind_field(size_t index, float&& v)
- {
- verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_C_FLOAT, &v, 0, &m_params[index].m_indicator));
- }
- void bind_field(size_t index, double&& v)
- {
- verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_C_DOUBLE, &v, 0, &m_params[index].m_indicator));
- }
- void bind_field(size_t index, DATE_STRUCT&& v)
- {
- verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_C_TYPE_DATE, &v, 0, &m_params[index].m_indicator));
- }
- void bind_field(size_t index, TIME_STRUCT&& v)
- {
- verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_C_TYPE_TIME, &v, 0, &m_params[index].m_indicator));
- }
- void bind_field(size_t index, TIMESTAMP_STRUCT&& v)
- {
- verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_C_TYPE_TIMESTAMP, &v, 0, &m_params[index].m_indicator));
- }
- void bind_field(size_t index, SQLGUID&& v)
- {
- verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_C_GUID, &v, 0, &m_params[index].m_indicator));
- }
- void bind_field(size_t index, SQL_NUMERIC_STRUCT&& v)
- {
- verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_C_NUMERIC, &v, 0, &m_params[index].m_indicator));
- }
- void bind_field(size_t index, char* v, size_t n)
- {
- m_params[index].m_data=v;
- m_params[index].m_size=n;
- m_params[index].m_after_fetch=[](const param_data& p) {
- if(p.m_indicator==SQL_NULL_DATA)
- memset(p.m_data, 0, p.m_size*sizeof(char));
- else
- {
- char* text=reinterpret_cast<char*>(p.m_data);
- text[p.m_indicator]='\0';
- }
+ protected:
+ SQLHANDLE m_handle;
};
- verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_C_CHAR, v, n, &m_params[index].m_indicator));
- }
- void bind_field(size_t index, wchar_t* v, size_t n)
- {
- m_params[index].m_data=v;
- m_params[index].m_size=n;
- m_params[index].m_after_fetch=[](const param_data& p) {
- if(p.m_indicator==SQL_NULL_DATA)
- memset(p.m_data, 0, p.m_size*sizeof(wchar_t));
- else
- {
- wchar_t* text=reinterpret_cast<wchar_t*>(p.m_data);
- text[p.m_indicator]='\0';
- }
- };
- verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_C_WCHAR, v, n, &m_params[index].m_indicator));
- }
- template<typename T>
- void bind_field(size_t index, qtl::bind_string_helper<T>&& v)
- {
- SQLLEN length=0;
- verify_error(SQLColAttribute(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_DESC_LENGTH, NULL, 0, NULL, &length));
- typename qtl::bind_string_helper<T>::char_type* data=v.alloc(length);
- bind_field(index, data, length+1);
- m_params[index].m_after_fetch=[v](const param_data& p) mutable {
- if(p.m_indicator==SQL_NULL_DATA)
- v.clear();
- else
- v.truncate(p.m_indicator);
- };
- }
- template<size_t N>
- void bind_field(size_t index, std::array<char, N>&& value)
- {
- bind_field(index, value.data(), value.size());
- }
- template<size_t N>
- void bind_field(size_t index, std::array<wchar_t, N>&& value)
- {
- bind_field(index, value.data(), value.size());
- }
- void bind_field(size_t index, qtl::blob_data&& v)
- {
- verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_C_BINARY, v.data, v.size, &m_params[index].m_indicator));
- }
- void bind_field(size_t index, std::ostream&& v)
- {
- if(m_blob_buffer==NULL)
- m_blob_buffer=malloc(blob_buffer_size);
- m_params[index].m_data=m_blob_buffer;
- m_params[index].m_size=blob_buffer_size;
- m_params[index].m_after_fetch=[this, index, &v](const param_data& p) {
- SQLRETURN ret=SQLGetData(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_C_BINARY, p.m_data, p.m_size, const_cast<SQLLEN*>(&p.m_indicator));
- while(ret!=SQL_NO_DATA)
- {
- size_t n = (p.m_indicator > blob_buffer_size) || (p.m_indicator == SQL_NO_TOTAL) ?
- blob_buffer_size : p.m_indicator;
- verify_error(ret);
- v.write((const char*)p.m_data, n);
- ret=SQLGetData(m_handle, static_cast<SQLUSMALLINT>(index+1), SQL_C_BINARY, p.m_data, p.m_size, const_cast<SQLLEN*>(&p.m_indicator));
- }
- };
- }
- void bind_field(size_t index, blobbuf&& value)
- {
- m_params[index].m_data = nullptr;
- m_params[index].m_size = 0;
- m_params[index].m_after_fetch = [this, index, &value](const param_data& p) {
- value.open(this, static_cast<SQLSMALLINT>(index), std::ios::in);
- };
- }
+ class blobbuf : public qtl::blobbuf
+ {
+ public:
+ blobbuf() : m_stmt(nullptr), m_field(0)
+ {
+ }
+ blobbuf(const blobbuf &) = default;
+ blobbuf &operator=(const blobbuf &) = default;
+ virtual ~blobbuf() { overflow(); }
- template<typename Type>
- void bind_field(size_t index, indicator<Type>&& value)
- {
- qtl::bind_field(*this, index, value.data);
- param_data& param=m_params[index];
- auto fetch_fun=param.m_after_fetch;
- param.m_after_fetch=[fetch_fun, &value](const param_data& p) {
- value.is_truncated=false;
- if(p.m_indicator==SQL_NULL_DATA)
+ void open(object<SQL_HANDLE_STMT> *stmt, SQLSMALLINT field, std::ios_base::openmode mode)
{
- value.is_null=true;
- value.length=0;
+ if (m_stmt && m_field)
+ {
+ overflow();
+ }
+
+ assert(stmt != SQL_NULL_HANDLE);
+ m_stmt = stmt;
+ m_field = field;
+ m_size = INTMAX_MAX;
+ init_buffer(mode);
}
- else if(p.m_indicator>=0)
+
+ private:
+ object<SQL_HANDLE_STMT> *m_stmt;
+ SQLSMALLINT m_field;
+
+ protected:
+ virtual bool read_blob(char *buffer, off_type &count, pos_type position) override
{
- value.is_null=false;
- value.length=p.m_indicator;
- if(p.m_size>0 && p.m_indicator>=p.m_size)
- value.is_truncated=true;
+ SQLLEN indicator = 0;
+ SQLRETURN ret = SQLGetData(m_stmt->handle(), m_field + 1, SQL_C_BINARY, buffer, static_cast<SQLINTEGER>(count), const_cast<SQLLEN *>(&indicator));
+ if (ret != SQL_NO_DATA)
+ {
+ count = (indicator > count) || (indicator == SQL_NO_TOTAL) ? count : indicator;
+ m_stmt->verify_error(ret);
+ return true;
+ }
+ else
+ return false;
}
- if(fetch_fun) fetch_fun(p);
+
+ virtual void write_blob(const char *buffer, size_t count) override
+ {
+ m_stmt->verify_error(SQLPutData(m_stmt->handle(), (SQLPOINTER)buffer, count));
+ }
};
- }
+
+ class environment final : public object<SQL_HANDLE_ENV>
+ {
+ public:
+ environment() : object(SQL_NULL_HANDLE)
+ {
+#if ODBCVER >= 0x0380
+ const SQLPOINTER version = (SQLPOINTER)SQL_OV_ODBC3_80;
+#else
+ const SQLPOINTER version = (SQLPOINTER)SQL_OV_ODBC3;
+#endif
+ verify_error(SQLSetEnvAttr(m_handle, SQL_ATTR_ODBC_VERSION, version, SQL_IS_INTEGER));
+ }
+ environment(environment &&src) : object(std::forward<environment>(src)) {}
+
+ int32_t version() const
+ {
+ int32_t ver = 0;
+ verify_error(SQLGetEnvAttr(m_handle, SQL_ATTR_ODBC_VERSION, &ver, sizeof(DWORD), NULL));
+ return ver;
+ }
+ };
+
+ class base_statement : public object<SQL_HANDLE_STMT>
+ {
+ public:
+ explicit base_statement(base_database &db);
+ base_statement(base_statement &&src)
+ : object(std::forward<base_statement>(src)), m_params(std::forward<std::vector<param_data>>(src.m_params))
+ {
+ m_binded_cols = src.m_binded_cols;
+ src.m_binded_cols = false;
+ m_blob_buffer = src.m_blob_buffer;
+ src.m_blob_buffer = NULL;
+ }
+ ~base_statement()
+ {
+ if (m_blob_buffer)
+ free(m_blob_buffer);
+ }
+ base_statement &operator=(base_statement &&src)
+ {
+ if (this != &src)
+ {
+ object::operator=(std::forward<base_statement>(src));
+ m_params = std::forward<std::vector<param_data>>(src.m_params);
+ m_binded_cols = src.m_binded_cols;
+ src.m_binded_cols = false;
+ m_blob_buffer = src.m_blob_buffer;
+ src.m_blob_buffer = NULL;
+ }
+ return *this;
+ }
+
+ void bind_param(size_t index, const std::nullptr_t &)
+ {
+ m_params[index].m_indicator = SQL_NULL_DATA;
+ verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index + 1),
+ SQL_PARAM_INPUT, SQL_C_DEFAULT, SQL_DEFAULT, 0, 0, NULL, 0, &m_params[index].m_indicator));
+ }
+ void bind_param(size_t index, const qtl::null &)
+ {
+ bind_param(index, nullptr);
+ }
+ void bind_param(size_t index, const int8_t &v)
+ {
+ verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_PARAM_INPUT, SQL_C_STINYINT, SQL_TINYINT,
+ 0, 0, (SQLPOINTER)&v, 0, NULL));
+ }
+ void bind_param(size_t index, const uint8_t &v)
+ {
+ verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_PARAM_INPUT, SQL_C_UTINYINT, SQL_TINYINT,
+ 0, 0, (SQLPOINTER)&v, 0, NULL));
+ }
+ void bind_param(size_t index, const int16_t &v)
+ {
+ verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_PARAM_INPUT, SQL_C_SSHORT, SQL_SMALLINT,
+ 0, 0, (SQLPOINTER)&v, 0, NULL));
+ }
+ void bind_param(size_t index, const uint16_t &v)
+ {
+ verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_PARAM_INPUT, SQL_C_USHORT, SQL_SMALLINT,
+ 0, 0, (SQLPOINTER)&v, 0, NULL));
+ }
+ void bind_param(size_t index, const int32_t &v)
+ {
+ verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER,
+ 0, 0, (SQLPOINTER)&v, 0, NULL));
+ }
+ void bind_param(size_t index, const uint32_t &v)
+ {
+ verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER,
+ 0, 0, (SQLPOINTER)&v, 0, NULL));
+ }
+ void bind_param(size_t index, const int64_t &v)
+ {
+ verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_PARAM_INPUT, SQL_C_SBIGINT, SQL_BIGINT,
+ 0, 0, (SQLPOINTER)&v, 0, NULL));
+ }
+ void bind_param(size_t index, const uint64_t &v)
+ {
+ verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_PARAM_INPUT, SQL_C_UBIGINT, SQL_BIGINT,
+ 0, 0, (SQLPOINTER)&v, 0, NULL));
+ }
+ void bind_param(size_t index, const double &v)
+ {
+ verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DOUBLE,
+ 0, 0, (SQLPOINTER)&v, 0, NULL));
+ }
+ void bind_param(size_t index, const float &v)
+ {
+ verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_PARAM_INPUT, SQL_C_FLOAT, SQL_FLOAT,
+ 0, 0, (SQLPOINTER)&v, 0, NULL));
+ }
+ void bind_param(size_t index, const bool &v)
+ {
+ verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_PARAM_INPUT, SQL_C_BIT, SQL_BIT,
+ 0, 0, (SQLPOINTER)&v, 0, NULL));
+ }
+ void bind_param(size_t index, const DATE_STRUCT &v)
+ {
+ verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_PARAM_INPUT, SQL_C_DATE, SQL_DATE,
+ 0, 0, (SQLPOINTER)&v, 0, NULL));
+ }
+ void bind_param(size_t index, const TIME_STRUCT &v)
+ {
+ verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_PARAM_INPUT, SQL_C_TIME, SQL_TIME,
+ 0, 0, (SQLPOINTER)&v, 0, NULL));
+ }
+ void bind_param(size_t index, const TIMESTAMP_STRUCT &v)
+ {
+ verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_PARAM_INPUT, SQL_C_TIMESTAMP, SQL_TIMESTAMP,
+ 0, 0, (SQLPOINTER)&v, 0, NULL));
+ }
+ void bind_param(size_t index, const SQLGUID &v)
+ {
+ verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_PARAM_INPUT, SQL_C_GUID, SQL_GUID,
+ 0, 0, (SQLPOINTER)&v, 0, NULL));
+ }
+ void bind_param(size_t index, const SQL_NUMERIC_STRUCT &v)
+ {
+ verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_PARAM_INPUT, SQL_C_NUMERIC, SQL_NUMERIC,
+ 0, 0, (SQLPOINTER)&v, 0, NULL));
+ }
+ void bind_param(size_t index, const char *v, size_t n = SQL_NTS, SQLULEN size = 0)
+ {
+ m_params[index].m_indicator = n;
+ if (size == 0)
+ size = strlen(v);
+ verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR,
+ size, 0, (SQLPOINTER)v, 0, &m_params[index].m_indicator));
+ }
+ void bind_param(size_t index, const wchar_t *v, size_t n = SQL_NTS, SQLULEN size = 0)
+ {
+ m_params[index].m_indicator = n;
+ if (size == 0)
+ size = wcslen(v);
+ verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_PARAM_INPUT, SQL_C_WCHAR, SQL_WCHAR,
+ size, 0, (SQLPOINTER)v, 0, &m_params[index].m_indicator));
+ }
+ void bind_param(size_t index, const std::string &v)
+ {
+ bind_param(index, v.data(), v.size(), v.size());
+ }
+ void bind_param(size_t index, const std::wstring &v)
+ {
+ bind_param(index, v.data(), v.size(), v.size());
+ }
+ void bind_param(size_t index, const const_blob_data &v)
+ {
+ m_params[index].m_indicator = v.size;
+ verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_PARAM_INPUT, SQL_C_BINARY, SQL_BINARY,
+ v.size, 0, (SQLPOINTER)v.data, 0, &m_params[index].m_indicator));
+ }
+ void bind_param(size_t index, std::istream &s)
+ {
+ if (m_blob_buffer == NULL)
+ m_blob_buffer = malloc(blob_buffer_size);
+ m_params[index].m_data = m_blob_buffer;
+ m_params[index].m_size = blob_buffer_size;
+ m_params[index].m_indicator = SQL_LEN_DATA_AT_EXEC(m_params[index].m_size);
+ verify_error(SQLBindParameter(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY,
+ INT_MAX, 0, &m_params[index], 0, &m_params[index].m_indicator));
+ m_params[index].m_after_fetch = [this, &s](const param_data &p)
+ {
+ SQLLEN readed = SQL_NULL_DATA;
+ while (!s.eof() && !s.fail())
+ {
+ s.read((char *)p.m_data, p.m_size);
+ readed = (unsigned long)s.gcount();
+ if (readed > 0)
+ {
+ verify_error(SQLPutData(m_handle, p.m_data, readed));
+ }
+ }
+ };
+ }
+
+ void bind_param(size_t index, const blob_writer ¶m)
+ {
+ m_params[index].m_data = nullptr;
+ m_params[index].m_size = blob_buffer_size;
+ m_params[index].m_indicator = SQL_LEN_DATA_AT_EXEC(m_params[index].m_size);
+ verify_error(SQLBindParameter(m_handle, static_cast<SQLSMALLINT>(index + 1), SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY,
+ INT_MAX, 0, &m_params[index], 0, &m_params[index].m_indicator));
+ m_params[index].m_after_fetch = [this, index, ¶m](const param_data &b)
+ {
+ blobbuf buf;
+ buf.open(this, static_cast<SQLSMALLINT>(index), std::ios::out);
+ std::ostream s(&buf);
+ param(s);
+ };
+ }
+
+ void bind_field(size_t index, bool &&v)
+ {
+ verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_C_BIT, &v, 0, &m_params[index].m_indicator));
+ }
+ void bind_field(size_t index, int8_t &&v)
+ {
+ verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_C_STINYINT, &v, 0, &m_params[index].m_indicator));
+ }
+ void bind_field(size_t index, uint8_t &&v)
+ {
+ verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_C_UTINYINT, &v, 0, &m_params[index].m_indicator));
+ }
+ void bind_field(size_t index, int16_t &&v)
+ {
+ verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_C_SSHORT, &v, 0, &m_params[index].m_indicator));
+ }
+ void bind_field(size_t index, uint16_t &&v)
+ {
+ verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_C_USHORT, &v, 0, &m_params[index].m_indicator));
+ }
+ void bind_field(size_t index, int32_t &&v)
+ {
+ verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_C_SLONG, &v, 0, &m_params[index].m_indicator));
+ }
+ void bind_field(size_t index, uint32_t &&v)
+ {
+ verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_C_ULONG, &v, 0, &m_params[index].m_indicator));
+ }
+ void bind_field(size_t index, int64_t &&v)
+ {
+ verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_C_SBIGINT, &v, 0, &m_params[index].m_indicator));
+ }
+ void bind_field(size_t index, uint64_t &&v)
+ {
+ verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_C_UBIGINT, &v, 0, &m_params[index].m_indicator));
+ }
+ void bind_field(size_t index, float &&v)
+ {
+ verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_C_FLOAT, &v, 0, &m_params[index].m_indicator));
+ }
+ void bind_field(size_t index, double &&v)
+ {
+ verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_C_DOUBLE, &v, 0, &m_params[index].m_indicator));
+ }
+ void bind_field(size_t index, DATE_STRUCT &&v)
+ {
+ verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_C_TYPE_DATE, &v, 0, &m_params[index].m_indicator));
+ }
+ void bind_field(size_t index, TIME_STRUCT &&v)
+ {
+ verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_C_TYPE_TIME, &v, 0, &m_params[index].m_indicator));
+ }
+ void bind_field(size_t index, TIMESTAMP_STRUCT &&v)
+ {
+ verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_C_TYPE_TIMESTAMP, &v, 0, &m_params[index].m_indicator));
+ }
+ void bind_field(size_t index, SQLGUID &&v)
+ {
+ verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_C_GUID, &v, 0, &m_params[index].m_indicator));
+ }
+ void bind_field(size_t index, SQL_NUMERIC_STRUCT &&v)
+ {
+ verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_C_NUMERIC, &v, 0, &m_params[index].m_indicator));
+ }
+ void bind_field(size_t index, char *v, size_t n)
+ {
+ m_params[index].m_data = v;
+ m_params[index].m_size = n;
+ m_params[index].m_after_fetch = [](const param_data &p)
+ {
+ if (p.m_indicator == SQL_NULL_DATA)
+ memset(p.m_data, 0, p.m_size * sizeof(char));
+ else
+ {
+ char *text = reinterpret_cast<char *>(p.m_data);
+ text[p.m_indicator] = '\0';
+ }
+ };
+ verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_C_CHAR, v, n, &m_params[index].m_indicator));
+ }
+ void bind_field(size_t index, wchar_t *v, size_t n)
+ {
+ m_params[index].m_data = v;
+ m_params[index].m_size = n;
+ m_params[index].m_after_fetch = [](const param_data &p)
+ {
+ if (p.m_indicator == SQL_NULL_DATA)
+ memset(p.m_data, 0, p.m_size * sizeof(wchar_t));
+ else
+ {
+ wchar_t *text = reinterpret_cast<wchar_t *>(p.m_data);
+ text[p.m_indicator] = '\0';
+ }
+ };
+ verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_C_WCHAR, v, n, &m_params[index].m_indicator));
+ }
+ template <typename T>
+ void bind_field(size_t index, qtl::bind_string_helper<T> &&v)
+ {
+ SQLLEN length = 0;
+ verify_error(SQLColAttribute(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_DESC_LENGTH, NULL, 0, NULL, &length));
+ typename qtl::bind_string_helper<T>::char_type *data = v.alloc(length);
+ bind_field(index, data, length + 1);
+ m_params[index].m_after_fetch = [v](const param_data &p) mutable
+ {
+ if (p.m_indicator == SQL_NULL_DATA)
+ v.clear();
+ else
+ v.truncate(p.m_indicator);
+ };
+ }
+ template <size_t N>
+ void bind_field(size_t index, std::array<char, N> &&value)
+ {
+ bind_field(index, value.data(), value.size());
+ }
+ template <size_t N>
+ void bind_field(size_t index, std::array<wchar_t, N> &&value)
+ {
+ bind_field(index, value.data(), value.size());
+ }
+ void bind_field(size_t index, qtl::blob_data &&v)
+ {
+ verify_error(SQLBindCol(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_C_BINARY, v.data, v.size, &m_params[index].m_indicator));
+ }
+ void bind_field(size_t index, std::ostream &&v)
+ {
+ if (m_blob_buffer == NULL)
+ m_blob_buffer = malloc(blob_buffer_size);
+ m_params[index].m_data = m_blob_buffer;
+ m_params[index].m_size = blob_buffer_size;
+ m_params[index].m_after_fetch = [this, index, &v](const param_data &p)
+ {
+ SQLRETURN ret = SQLGetData(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_C_BINARY, p.m_data, p.m_size, const_cast<SQLLEN *>(&p.m_indicator));
+ while (ret != SQL_NO_DATA)
+ {
+ size_t n = (p.m_indicator > blob_buffer_size) || (p.m_indicator == SQL_NO_TOTAL) ? blob_buffer_size : p.m_indicator;
+ verify_error(ret);
+ v.write((const char *)p.m_data, n);
+ ret = SQLGetData(m_handle, static_cast<SQLUSMALLINT>(index + 1), SQL_C_BINARY, p.m_data, p.m_size, const_cast<SQLLEN *>(&p.m_indicator));
+ }
+ };
+ }
+
+ void bind_field(size_t index, blobbuf &&value)
+ {
+ m_params[index].m_data = nullptr;
+ m_params[index].m_size = 0;
+ m_params[index].m_after_fetch = [this, index, &value](const param_data &p)
+ {
+ value.open(this, static_cast<SQLSMALLINT>(index), std::ios::in);
+ };
+ }
+
+ template <typename Type>
+ void bind_field(size_t index, indicator<Type> &&value)
+ {
+ qtl::bind_field(*this, index, value.data);
+ param_data ¶m = m_params[index];
+ auto fetch_fun = param.m_after_fetch;
+ param.m_after_fetch = [fetch_fun, &value](const param_data &p)
+ {
+ value.is_truncated = false;
+ if (p.m_indicator == SQL_NULL_DATA)
+ {
+ value.is_null = true;
+ value.length = 0;
+ }
+ else if (p.m_indicator >= 0)
+ {
+ value.is_null = false;
+ value.length = p.m_indicator;
+ if (p.m_size > 0 && p.m_indicator >= p.m_size)
+ value.is_truncated = true;
+ }
+ if (fetch_fun)
+ fetch_fun(p);
+ };
+ }
#ifdef _QTL_ENABLE_CPP17
- template<typename Type>
- void bind_field(size_t index, std::optional<Type>&& value)
- {
- qtl::bind_field(*this, index, *value);
- param_data& param = m_params[index];
- auto fetch_fun = param.m_after_fetch;
- param.m_after_fetch = [fetch_fun, &value](const param_data& p) {
- if (fetch_fun) fetch_fun(p);
- if (p.m_indicator == SQL_NULL_DATA)
- value.reset();
- };
- }
+ template <typename Type>
+ void bind_field(size_t index, std::optional<Type> &&value)
+ {
+ qtl::bind_field(*this, index, *value);
+ param_data ¶m = m_params[index];
+ auto fetch_fun = param.m_after_fetch;
+ param.m_after_fetch = [fetch_fun, &value](const param_data &p)
+ {
+ if (fetch_fun)
+ fetch_fun(p);
+ if (p.m_indicator == SQL_NULL_DATA)
+ value.reset();
+ };
+ }
- void bind_field(size_t index, std::any&& value)
- {
- SQLLEN type = 0, isUnsigned=SQL_FALSE;
- verify_error(SQLColAttribute(m_handle, index + 1, SQL_DESC_TYPE, NULL, 0, NULL, &type));
- verify_error(SQLColAttribute(m_handle, index + 1, SQL_DESC_UNSIGNED, NULL, 0, NULL, &isUnsigned));
- switch (type)
- {
- case SQL_BIT:
- value.emplace<bool>();
- bind_field(index, std::forward<bool>(std::any_cast<bool&>(value)));
- break;
- case SQL_TINYINT:
- if (isUnsigned)
+ void bind_field(size_t index, std::any &&value)
{
- value.emplace<uint8_t>();
- bind_field(index, std::forward<uint8_t>(std::any_cast<uint8_t&>(value)));
+ SQLLEN type = 0, isUnsigned = SQL_FALSE;
+ verify_error(SQLColAttribute(m_handle, index + 1, SQL_DESC_TYPE, NULL, 0, NULL, &type));
+ verify_error(SQLColAttribute(m_handle, index + 1, SQL_DESC_UNSIGNED, NULL, 0, NULL, &isUnsigned));
+ switch (type)
+ {
+ case SQL_BIT:
+ value.emplace<bool>();
+ bind_field(index, std::forward<bool>(std::any_cast<bool &>(value)));
+ break;
+ case SQL_TINYINT:
+ if (isUnsigned)
+ {
+ value.emplace<uint8_t>();
+ bind_field(index, std::forward<uint8_t>(std::any_cast<uint8_t &>(value)));
+ }
+ else
+ {
+ value.emplace<int8_t>();
+ bind_field(index, std::forward<int8_t>(std::any_cast<int8_t &>(value)));
+ }
+ break;
+ case SQL_SMALLINT:
+ if (isUnsigned)
+ {
+ value.emplace<uint16_t>();
+ bind_field(index, std::forward<uint16_t>(std::any_cast<uint16_t &>(value)));
+ }
+ else
+ {
+ value.emplace<int16_t>();
+ bind_field(index, std::forward<int16_t>(std::any_cast<int16_t &>(value)));
+ }
+ break;
+ case SQL_INTEGER:
+ if (isUnsigned)
+ {
+ value.emplace<uint32_t>();
+ bind_field(index, std::forward<uint32_t>(std::any_cast<uint32_t &>(value)));
+ }
+ else
+ {
+ value.emplace<int32_t>();
+ bind_field(index, std::forward<int32_t>(std::any_cast<int32_t &>(value)));
+ }
+ break;
+ case SQL_BIGINT:
+ if (isUnsigned)
+ {
+ value.emplace<uint64_t>();
+ bind_field(index, std::forward<uint64_t>(std::any_cast<uint64_t &>(value)));
+ }
+ else
+ {
+ value.emplace<int64_t>();
+ bind_field(index, std::forward<int64_t>(std::any_cast<int64_t &>(value)));
+ }
+ break;
+ case SQL_FLOAT:
+ value.emplace<float>();
+ bind_field(index, std::forward<float>(std::any_cast<float &>(value)));
+ break;
+ case SQL_DOUBLE:
+ value.emplace<double>();
+ bind_field(index, std::forward<double>(std::any_cast<double &>(value)));
+ break;
+ case SQL_NUMERIC:
+ value.emplace<SQL_NUMERIC_STRUCT>();
+ bind_field(index, std::forward<SQL_NUMERIC_STRUCT>(std::any_cast<SQL_NUMERIC_STRUCT &>(value)));
+ break;
+ case SQL_TIME:
+ value.emplace<SQL_TIME_STRUCT>();
+ bind_field(index, std::forward<SQL_TIME_STRUCT>(std::any_cast<SQL_TIME_STRUCT &>(value)));
+ break;
+ case SQL_DATE:
+ value.emplace<SQL_DATE_STRUCT>();
+ bind_field(index, std::forward<SQL_DATE_STRUCT>(std::any_cast<SQL_DATE_STRUCT &>(value)));
+ break;
+ case SQL_TIMESTAMP:
+ value.emplace<SQL_TIMESTAMP_STRUCT>();
+ bind_field(index, std::forward<SQL_TIMESTAMP_STRUCT>(std::any_cast<SQL_TIMESTAMP_STRUCT &>(value)));
+ break;
+ case SQL_INTERVAL_MONTH:
+ case SQL_INTERVAL_YEAR:
+ case SQL_INTERVAL_YEAR_TO_MONTH:
+ case SQL_INTERVAL_DAY:
+ case SQL_INTERVAL_HOUR:
+ case SQL_INTERVAL_MINUTE:
+ case SQL_INTERVAL_SECOND:
+ case SQL_INTERVAL_DAY_TO_HOUR:
+ case SQL_INTERVAL_DAY_TO_MINUTE:
+ case SQL_INTERVAL_DAY_TO_SECOND:
+ case SQL_INTERVAL_HOUR_TO_MINUTE:
+ case SQL_INTERVAL_HOUR_TO_SECOND:
+ case SQL_INTERVAL_MINUTE_TO_SECOND:
+ value.emplace<SQL_INTERVAL_STRUCT>();
+ bind_field(index, std::forward<SQL_INTERVAL_STRUCT>(std::any_cast<SQL_INTERVAL_STRUCT &>(value)));
+ break;
+ case SQL_CHAR:
+ value.emplace<std::string>();
+ bind_field(index, qtl::bind_string(std::any_cast<std::string &>(value)));
+ break;
+ case SQL_GUID:
+ value.emplace<SQLGUID>();
+ bind_field(index, std::forward<SQLGUID>(std::any_cast<SQLGUID &>(value)));
+ break;
+ case SQL_BINARY:
+ value.emplace<blobbuf>();
+ bind_field(index, std::forward<blobbuf>(std::any_cast<blobbuf &>(value)));
+ break;
+ default:
+ throw odbc::error(*this, SQL_ERROR);
+ }
+ param_data ¶m = m_params[index];
+ auto fetch_fun = param.m_after_fetch;
+ param.m_after_fetch = [fetch_fun, &value](const param_data &p)
+ {
+ if (fetch_fun)
+ fetch_fun(p);
+ if (p.m_indicator == SQL_NULL_DATA)
+ value.reset();
+ };
}
- else
- {
- value.emplace<int8_t>();
- bind_field(index, std::forward<int8_t>(std::any_cast<int8_t&>(value)));
- }
- break;
- case SQL_SMALLINT:
- if (isUnsigned)
- {
- value.emplace<uint16_t>();
- bind_field(index, std::forward<uint16_t>(std::any_cast<uint16_t&>(value)));
- }
- else
- {
- value.emplace<int16_t>();
- bind_field(index, std::forward<int16_t>(std::any_cast<int16_t&>(value)));
- }
- break;
- case SQL_INTEGER:
- if (isUnsigned)
- {
- value.emplace<uint32_t>();
- bind_field(index, std::forward<uint32_t>(std::any_cast<uint32_t&>(value)));
- }
- else
- {
- value.emplace<int32_t>();
- bind_field(index, std::forward<int32_t>(std::any_cast<int32_t&>(value)));
- }
- break;
- case SQL_BIGINT:
- if (isUnsigned)
- {
- value.emplace<uint64_t>();
- bind_field(index, std::forward<uint64_t>(std::any_cast<uint64_t&>(value)));
- }
- else
- {
- value.emplace<int64_t>();
- bind_field(index, std::forward<int64_t>(std::any_cast<int64_t&>(value)));
- }
- break;
- case SQL_FLOAT:
- value.emplace<float>();
- bind_field(index, std::forward<float>(std::any_cast<float&>(value)));
- break;
- case SQL_DOUBLE:
- value.emplace<double>();
- bind_field(index, std::forward<double>(std::any_cast<double&>(value)));
- break;
- case SQL_NUMERIC:
- value.emplace<SQL_NUMERIC_STRUCT>();
- bind_field(index, std::forward<SQL_NUMERIC_STRUCT>(std::any_cast<SQL_NUMERIC_STRUCT&>(value)));
- break;
- case SQL_TIME:
- value.emplace<SQL_TIME_STRUCT>();
- bind_field(index, std::forward<SQL_TIME_STRUCT>(std::any_cast<SQL_TIME_STRUCT&>(value)));
- break;
- case SQL_DATE:
- value.emplace<SQL_DATE_STRUCT>();
- bind_field(index, std::forward<SQL_DATE_STRUCT>(std::any_cast<SQL_DATE_STRUCT&>(value)));
- break;
- case SQL_TIMESTAMP:
- value.emplace<SQL_TIMESTAMP_STRUCT>();
- bind_field(index, std::forward<SQL_TIMESTAMP_STRUCT>(std::any_cast<SQL_TIMESTAMP_STRUCT&>(value)));
- break;
- case SQL_INTERVAL_MONTH:
- case SQL_INTERVAL_YEAR:
- case SQL_INTERVAL_YEAR_TO_MONTH:
- case SQL_INTERVAL_DAY:
- case SQL_INTERVAL_HOUR:
- case SQL_INTERVAL_MINUTE:
- case SQL_INTERVAL_SECOND:
- case SQL_INTERVAL_DAY_TO_HOUR:
- case SQL_INTERVAL_DAY_TO_MINUTE:
- case SQL_INTERVAL_DAY_TO_SECOND:
- case SQL_INTERVAL_HOUR_TO_MINUTE:
- case SQL_INTERVAL_HOUR_TO_SECOND:
- case SQL_INTERVAL_MINUTE_TO_SECOND:
- value.emplace<SQL_INTERVAL_STRUCT>();
- bind_field(index, std::forward<SQL_INTERVAL_STRUCT>(std::any_cast<SQL_INTERVAL_STRUCT&>(value)));
- break;
- case SQL_CHAR:
- value.emplace<std::string>();
- bind_field(index, qtl::bind_string(std::any_cast<std::string&>(value)));
- break;
- case SQL_GUID:
- value.emplace<SQLGUID>();
- bind_field(index, std::forward<SQLGUID>(std::any_cast<SQLGUID&>(value)));
- break;
- case SQL_BINARY:
- value.emplace<blobbuf>();
- bind_field(index, std::forward<blobbuf>(std::any_cast<blobbuf&>(value)));
- break;
- default:
- throw odbc::error(*this, SQL_ERROR);
- }
- param_data& param = m_params[index];
- auto fetch_fun = param.m_after_fetch;
- param.m_after_fetch = [fetch_fun, &value](const param_data& p) {
- if (fetch_fun) fetch_fun(p);
- if (p.m_indicator == SQL_NULL_DATA)
- value.reset();
- };
- }
#endif // C++17
- SQLLEN affetced_rows()
- {
- SQLLEN count=0;
- verify_error(SQLRowCount(m_handle, &count));
- return count;
- }
-
- size_t find_field(const char* name) const
- {
- SQLSMALLINT count=0;
- verify_error(SQLNumResultCols(m_handle, &count));
- for(SQLSMALLINT i=0; i!=count; i++)
- {
- SQLCHAR field_name[256]={0};
- SQLSMALLINT name_length=0;
- SQLSMALLINT data_type;
- SQLULEN column_size;
- SQLSMALLINT digits;
- SQLSMALLINT nullable;
- verify_error(SQLDescribeColA(m_handle, i, field_name, sizeof(field_name), &name_length,
- &data_type, &column_size, &digits, &nullable));
- if(strncmp((char*)field_name, name, name_length)==0)
- return i;
- }
- return -1;
- }
-
- void reset()
- {
- verify_error(SQLFreeStmt(m_handle, SQL_RESET_PARAMS));
- }
-
- /*
- ODBC do not support this function, but you can use query to instead it:
- For MS SQL Server: SELECT @@IDENTITY;
- For MySQL: SELECT LAST_INSERT_ID();
- For SQLite: SELECT last_insert_rowid();
- */
- /*uint64_t insert_id()
- {
- assert(false);
- return 0;
- }*/
-
-protected:
- struct param_data
- {
- SQLPOINTER m_data;
- SQLLEN m_size;
- SQLLEN m_indicator;
- std::function<void(const param_data&)> m_after_fetch;
-
- param_data() : m_data(NULL), m_size(0), m_indicator(0) { }
- };
- SQLPOINTER m_blob_buffer;
- std::vector<param_data> m_params;
- bool m_binded_cols;
-};
-
-class statement : public base_statement
-{
-public:
- statement() = default;
- explicit statement(base_database& db) : base_statement(db) { }
- statement(statement&& src) : base_statement(std::move(src)) { }
- statement& operator=(statement&& src)
- {
- base_statement::operator =(std::move(src));
- return *this;
- }
- ~statement()
- {
- close();
- }
-
- void open(const char* query_text, size_t text_length = SQL_NTS)
- {
- reset();
- verify_error(SQLPrepareA(m_handle, (SQLCHAR*)query_text, text_length));
- }
- void open(const std::string& query_text)
- {
- open(query_text.data(), query_text.size());
- }
-
-
- template<typename Types>
- void execute(const Types& params)
- {
- SQLSMALLINT count = 0;
- verify_error(SQLNumParams(m_handle, &count));
- if (count > 0)
- {
- m_params.resize(count);
- qtl::bind_params(*this, params);
- }
-
- SQLRETURN ret = SQLExecute(m_handle);
- verify_error(ret);
- if (ret == SQL_NEED_DATA)
- {
- SQLPOINTER token;
- size_t i = 0;
- ret = SQLParamData(m_handle, &token);
- verify_error(ret);
- while (ret == SQL_NEED_DATA)
+ SQLLEN affetced_rows()
{
- while (i != count)
+ SQLLEN count = 0;
+ verify_error(SQLRowCount(m_handle, &count));
+ return count;
+ }
+
+ size_t find_field(const char *name) const
+ {
+ SQLSMALLINT count = 0;
+ verify_error(SQLNumResultCols(m_handle, &count));
+ for (SQLSMALLINT i = 0; i != count; i++)
{
- if (&m_params[i] == token)
- {
- if (m_params[i].m_after_fetch)
- m_params[i].m_after_fetch(m_params[i]);
- break;
- }
- ++i;
+ SQLCHAR field_name[256] = {0};
+ SQLSMALLINT name_length = 0;
+ SQLSMALLINT data_type;
+ SQLULEN column_size;
+ SQLSMALLINT digits;
+ SQLSMALLINT nullable;
+ verify_error(SQLDescribeColA(m_handle, i, field_name, sizeof(field_name), &name_length,
+ &data_type, &column_size, &digits, &nullable));
+ if (strncmp((char *)field_name, name, name_length) == 0)
+ return i;
}
- ret = SQLParamData(m_handle, &token);
- verify_error(ret);
+ return -1;
}
- }
- }
- template<typename Types>
- bool fetch(Types&& values)
- {
- if (!m_binded_cols)
- {
- SQLSMALLINT count = 0;
- verify_error(SQLNumResultCols(m_handle, &count));
- if (count > 0)
+ void reset()
{
- m_params.resize(count);
- qtl::bind_record(*this, std::forward<Types>(values));
+ verify_error(SQLFreeStmt(m_handle, SQL_RESET_PARAMS));
}
- m_binded_cols = true;
- }
- return fetch();
- }
- bool fetch()
- {
- SQLRETURN ret = SQLFetch(m_handle);
- if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
- {
- for (const param_data& data : m_params)
+ /*
+ ODBC do not support this function, but you can use query to instead it:
+ For MS SQL Server: SELECT @@IDENTITY;
+ For MySQL: SELECT LAST_INSERT_ID();
+ For SQLite: SELECT last_insert_rowid();
+ */
+ /*uint64_t insert_id()
{
- if (data.m_after_fetch)
- data.m_after_fetch(data);
+ assert(false);
+ return 0;
+ }*/
+
+ protected:
+ struct param_data
+ {
+ SQLPOINTER m_data;
+ SQLLEN m_size;
+ SQLLEN m_indicator;
+ std::function<void(const param_data &)> m_after_fetch;
+
+ param_data() : m_data(NULL), m_size(0), m_indicator(0) {}
+ };
+ SQLPOINTER m_blob_buffer;
+ std::vector<param_data> m_params;
+ bool m_binded_cols;
+ };
+
+ class statement : public base_statement
+ {
+ public:
+ statement() = default;
+ explicit statement(base_database &db) : base_statement(db) {}
+ statement(statement &&src) : base_statement(std::move(src)) {}
+ statement &operator=(statement &&src)
+ {
+ base_statement::operator=(std::move(src));
+ return *this;
}
- return true;
- }
- verify_error(ret);
- return false;
- }
+ ~statement()
+ {
+ close();
+ }
- bool next_result()
- {
- SQLRETURN ret;
- SQLSMALLINT count = 0;
- m_binded_cols = false;
- do
- {
- ret = SQLMoreResults(m_handle);
- if (ret == SQL_ERROR || ret == SQL_INVALID_HANDLE)
+ void open(const char *query_text, size_t text_length = SQL_NTS)
+ {
+ reset();
+ verify_error(SQLPrepareA(m_handle, (SQLCHAR *)query_text, text_length));
+ }
+ void open(const std::string &query_text)
+ {
+ open(query_text.data(), query_text.size());
+ }
+
+ template <typename Types>
+ void execute(const Types ¶ms)
+ {
+ SQLSMALLINT count = 0;
+ verify_error(SQLNumParams(m_handle, &count));
+ if (count > 0)
+ {
+ m_params.resize(count);
+ qtl::bind_params(*this, params);
+ }
+
+ SQLRETURN ret = SQLExecute(m_handle);
verify_error(ret);
- verify_error(SQLNumResultCols(m_handle, &count));
- } while (count == 0);
- return ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO;
- }
-};
+ if (ret == SQL_NEED_DATA)
+ {
+ SQLPOINTER token;
+ size_t i = 0;
+ ret = SQLParamData(m_handle, &token);
+ verify_error(ret);
+ while (ret == SQL_NEED_DATA)
+ {
+ while (i != count)
+ {
+ if (&m_params[i] == token)
+ {
+ if (m_params[i].m_after_fetch)
+ m_params[i].m_after_fetch(m_params[i]);
+ break;
+ }
+ ++i;
+ }
+ ret = SQLParamData(m_handle, &token);
+ verify_error(ret);
+ }
+ }
+ }
-struct connection_parameter
-{
- std::string m_name;
- std::string m_prompt;
- std::string m_value;
- std::vector<std::string> m_value_list;
- bool m_optinal;
- bool m_assigned;
+ template <typename Types>
+ bool fetch(Types &&values)
+ {
+ if (!m_binded_cols)
+ {
+ SQLSMALLINT count = 0;
+ verify_error(SQLNumResultCols(m_handle, &count));
+ if (count > 0)
+ {
+ m_params.resize(count);
+ qtl::bind_record(*this, std::forward<Types>(values));
+ }
+ m_binded_cols = true;
+ }
+ return fetch();
+ }
- connection_parameter() : m_optinal(false), m_assigned(false) { }
- void reset()
- {
- m_name.clear();
- m_prompt.clear();
- m_value.clear();
- m_value_list.clear();
- m_optinal=false;
- m_assigned=false;
- }
-};
-typedef std::vector<connection_parameter> connection_parameters;
+ bool fetch()
+ {
+ SQLRETURN ret = SQLFetch(m_handle);
+ if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
+ {
+ for (const param_data &data : m_params)
+ {
+ if (data.m_after_fetch)
+ data.m_after_fetch(data);
+ }
+ return true;
+ }
+ verify_error(ret);
+ return false;
+ }
-class base_database : public object<SQL_HANDLE_DBC>
-{
-public:
- typedef odbc::error exception_type;
+ bool next_result()
+ {
+ SQLRETURN ret;
+ SQLSMALLINT count = 0;
+ m_binded_cols = false;
+ do
+ {
+ ret = SQLMoreResults(m_handle);
+ if (ret == SQL_ERROR || ret == SQL_INVALID_HANDLE)
+ verify_error(ret);
+ verify_error(SQLNumResultCols(m_handle, &count));
+ } while (count == 0);
+ return ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO;
+ }
+ };
- explicit base_database(environment& env) : object(env.handle()), m_opened(false)
- {
- }
- base_database(const base_database&) = delete;
- base_database(base_database&& src)
- : object(std::forward<base_database>(src)), m_connection(std::forward<std::string>(src.m_connection))
- {
- m_opened=src.m_opened;
- src.m_opened=false;
- }
- ~base_database()
- {
- close();
- }
- base_database& operator=(base_database&& src)
- {
- if(this!=&src)
+ struct connection_parameter
{
- object::operator =(std::forward<base_database>(src));
- m_opened=src.m_opened;
- src.m_opened=false;
- m_connection=std::forward<std::string>(src.m_connection);
- }
- return *this;
- }
+ std::string m_name;
+ std::string m_prompt;
+ std::string m_value;
+ std::vector<std::string> m_value_list;
+ bool m_optinal;
+ bool m_assigned;
- void close()
- {
- if(m_opened)
+ connection_parameter() : m_optinal(false), m_assigned(false) {}
+ void reset()
+ {
+ m_name.clear();
+ m_prompt.clear();
+ m_value.clear();
+ m_value_list.clear();
+ m_optinal = false;
+ m_assigned = false;
+ }
+ };
+ typedef std::vector<connection_parameter> connection_parameters;
+
+ class base_database : public object<SQL_HANDLE_DBC>
{
- verify_error(SQLDisconnect(m_handle));
- m_opened=false;
- }
- }
+ public:
+ typedef odbc::error exception_type;
- void set_attribute(SQLINTEGER attr, SQLPOINTER value)
- {
- verify_error(SQLSetConnectAttrA(m_handle, attr, (SQLPOINTER)value, SQL_IS_POINTER));
- }
- void set_attribute(SQLINTEGER attr, SQLINTEGER value)
- {
- verify_error(SQLSetConnectAttrA(m_handle, attr, (SQLPOINTER)value, SQL_IS_INTEGER));
- }
- void set_attribute(SQLINTEGER attr, SQLUINTEGER value)
- {
- verify_error(SQLSetConnectAttrA(m_handle, attr, (SQLPOINTER)value, SQL_IS_UINTEGER));
- }
- void set_attribute(SQLINTEGER attr, SQLSMALLINT value)
- {
- verify_error(SQLSetConnectAttrA(m_handle, attr, (SQLPOINTER)value, SQL_IS_SMALLINT));
- }
- void set_attribute(SQLINTEGER attr, SQLUSMALLINT value)
- {
- verify_error(SQLSetConnectAttrA(m_handle, attr, (SQLPOINTER)value, SQL_IS_USMALLINT));
- }
- void set_attribute(SQLINTEGER attr, const char* value)
- {
- verify_error(SQLSetConnectAttrA(m_handle, attr, (SQLPOINTER)value, SQL_NTS));
- }
- void set_attribute(SQLINTEGER attr, const std::string& value)
- {
- verify_error(SQLSetConnectAttrA(m_handle, attr, (SQLPOINTER)value.data(), value.size()));
- }
- void set_attribute(SQLINTEGER attr, const void* value, SQLINTEGER length)
- {
- verify_error(SQLSetConnectAttrA(m_handle, attr, (SQLPOINTER)value, SQL_LEN_BINARY_ATTR(length)));
- }
- void get_attribute(SQLINTEGER attr, SQLPOINTER& value) const
- {
- verify_error(SQLGetConnectAttrA(m_handle, attr, &value, SQL_IS_POINTER, 0));
- }
- void get_attribute(SQLINTEGER attr, SQLINTEGER& value) const
- {
- value = 0;
- verify_error(SQLGetConnectAttrA(m_handle, attr, &value, SQL_IS_INTEGER, 0));
- }
- void get_attribute(SQLINTEGER attr, SQLUINTEGER& value) const
- {
- value = 0;
- verify_error(SQLGetConnectAttrA(m_handle, attr, &value, SQL_IS_UINTEGER, 0));
- }
- void get_attribute(SQLINTEGER attr, SQLSMALLINT& value) const
- {
- value = 0;
- verify_error(SQLGetConnectAttrA(m_handle, attr, &value, SQL_IS_SMALLINT, 0));
- }
- void get_attribute(SQLINTEGER attr, SQLUSMALLINT& value) const
- {
- value = 0;
- verify_error(SQLGetConnectAttrA(m_handle, attr, &value, SQL_IS_USMALLINT, 0));
- }
- void get_attribute(SQLINTEGER attr, void* buffer, SQLINTEGER length) const
- {
- verify_error(SQLGetConnectAttrA(m_handle, attr, buffer, SQL_LEN_BINARY_ATTR(length), 0));
- }
- void get_attribute(SQLINTEGER attr, char* buffer, size_t length) const
- {
- verify_error(SQLGetConnectAttrA(m_handle, attr, buffer, length, 0));
- }
- void get_attribute(SQLINTEGER attr, std::string& value) const
- {
- SQLINTEGER length = 0;
- verify_error(SQLGetConnectAttrA(m_handle, attr, NULL, 0, &length));
- value.resize(length);
- if(length>0)
- verify_error(SQLGetConnectAttrA(m_handle, attr, (SQLPOINTER)value.data(), length, 0));
- }
- void get_info(SQLSMALLINT info, std::string& value, SQLSMALLINT size=SQL_MAX_OPTION_STRING_LENGTH) const
- {
- value.resize(size);
- verify_error(SQLGetInfo(m_handle, info, (SQLPOINTER)value.data(), size, &size));
- value.resize(size);
- }
+ explicit base_database(environment &env) : object(env.handle()), m_opened(false)
+ {
+ }
+ base_database(const base_database &) = delete;
+ base_database(base_database &&src)
+ : object(std::forward<base_database>(src)), m_connection(std::forward<std::string>(src.m_connection))
+ {
+ m_opened = src.m_opened;
+ src.m_opened = false;
+ }
+ ~base_database()
+ {
+ close();
+ }
+ base_database &operator=(base_database &&src)
+ {
+ if (this != &src)
+ {
+ object::operator=(std::forward<base_database>(src));
+ m_opened = src.m_opened;
+ src.m_opened = false;
+ m_connection = std::forward<std::string>(src.m_connection);
+ }
+ return *this;
+ }
- std::string dbms_name() const
- {
- std::string name;
- get_info(SQL_DBMS_NAME, name);
- return name;
- }
- std::string server_name() const
- {
- std::string name;
- get_info(SQL_SERVER_NAME, name);
- return name;
- }
- std::string user_name() const
- {
- std::string name;
- get_info(SQL_USER_NAME, name);
- return name;
- }
- std::string db_name() const
- {
- std::string name;
- get_info(SQL_DATABASE_NAME, name);
- return name;
- }
- const std::string& connection_text() const
- {
- return m_connection;
- }
+ void close()
+ {
+ if (m_opened)
+ {
+ verify_error(SQLDisconnect(m_handle));
+ m_opened = false;
+ }
+ }
-protected:
- bool m_opened;
- std::string m_connection;
+ void set_attribute(SQLINTEGER attr, SQLPOINTER value)
+ {
+ verify_error(SQLSetConnectAttrA(m_handle, attr, (SQLPOINTER)value, SQL_IS_POINTER));
+ }
+ void set_attribute(SQLINTEGER attr, SQLINTEGER value)
+ {
+ verify_error(SQLSetConnectAttrA(m_handle, attr, (SQLPOINTER)value, SQL_IS_INTEGER));
+ }
+ void set_attribute(SQLINTEGER attr, SQLUINTEGER value)
+ {
+ verify_error(SQLSetConnectAttrA(m_handle, attr, (SQLPOINTER)value, SQL_IS_UINTEGER));
+ }
+ void set_attribute(SQLINTEGER attr, SQLSMALLINT value)
+ {
+ verify_error(SQLSetConnectAttrA(m_handle, attr, (SQLPOINTER)value, SQL_IS_SMALLINT));
+ }
+ void set_attribute(SQLINTEGER attr, SQLUSMALLINT value)
+ {
+ verify_error(SQLSetConnectAttrA(m_handle, attr, (SQLPOINTER)value, SQL_IS_USMALLINT));
+ }
+ void set_attribute(SQLINTEGER attr, const char *value)
+ {
+ verify_error(SQLSetConnectAttrA(m_handle, attr, (SQLPOINTER)value, SQL_NTS));
+ }
+ void set_attribute(SQLINTEGER attr, const std::string &value)
+ {
+ verify_error(SQLSetConnectAttrA(m_handle, attr, (SQLPOINTER)value.data(), value.size()));
+ }
+ void set_attribute(SQLINTEGER attr, const void *value, SQLINTEGER length)
+ {
+ verify_error(SQLSetConnectAttrA(m_handle, attr, (SQLPOINTER)value, SQL_LEN_BINARY_ATTR(length)));
+ }
+ void get_attribute(SQLINTEGER attr, SQLPOINTER &value) const
+ {
+ verify_error(SQLGetConnectAttrA(m_handle, attr, &value, SQL_IS_POINTER, 0));
+ }
+ void get_attribute(SQLINTEGER attr, SQLINTEGER &value) const
+ {
+ value = 0;
+ verify_error(SQLGetConnectAttrA(m_handle, attr, &value, SQL_IS_INTEGER, 0));
+ }
+ void get_attribute(SQLINTEGER attr, SQLUINTEGER &value) const
+ {
+ value = 0;
+ verify_error(SQLGetConnectAttrA(m_handle, attr, &value, SQL_IS_UINTEGER, 0));
+ }
+ void get_attribute(SQLINTEGER attr, SQLSMALLINT &value) const
+ {
+ value = 0;
+ verify_error(SQLGetConnectAttrA(m_handle, attr, &value, SQL_IS_SMALLINT, 0));
+ }
+ void get_attribute(SQLINTEGER attr, SQLUSMALLINT &value) const
+ {
+ value = 0;
+ verify_error(SQLGetConnectAttrA(m_handle, attr, &value, SQL_IS_USMALLINT, 0));
+ }
+ void get_attribute(SQLINTEGER attr, void *buffer, SQLINTEGER length) const
+ {
+ verify_error(SQLGetConnectAttrA(m_handle, attr, buffer, SQL_LEN_BINARY_ATTR(length), 0));
+ }
+ void get_attribute(SQLINTEGER attr, char *buffer, size_t length) const
+ {
+ verify_error(SQLGetConnectAttrA(m_handle, attr, buffer, length, 0));
+ }
+ void get_attribute(SQLINTEGER attr, std::string &value) const
+ {
+ SQLINTEGER length = 0;
+ verify_error(SQLGetConnectAttrA(m_handle, attr, NULL, 0, &length));
+ value.resize(length);
+ if (length > 0)
+ verify_error(SQLGetConnectAttrA(m_handle, attr, (SQLPOINTER)value.data(), length, 0));
+ }
+ void get_info(SQLSMALLINT info, std::string &value, SQLSMALLINT size = SQL_MAX_OPTION_STRING_LENGTH) const
+ {
+ value.resize(size);
+ verify_error(SQLGetInfo(m_handle, info, (SQLPOINTER)value.data(), size, &size));
+ value.resize(size);
+ }
- void parse_browse_string(const char* output_text, size_t text_length, connection_parameters& parameters);
- std::string create_connection_text(const connection_parameters& parameters);
-};
+ std::string dbms_name() const
+ {
+ std::string name;
+ get_info(SQL_DBMS_NAME, name);
+ return name;
+ }
+ std::string server_name() const
+ {
+ std::string name;
+ get_info(SQL_SERVER_NAME, name);
+ return name;
+ }
+ std::string user_name() const
+ {
+ std::string name;
+ get_info(SQL_USER_NAME, name);
+ return name;
+ }
+ std::string db_name() const
+ {
+ std::string name;
+ get_info(SQL_DATABASE_NAME, name);
+ return name;
+ }
+ const std::string &connection_text() const
+ {
+ return m_connection;
+ }
-class database : public base_database, public qtl::base_database<database, statement>
-{
-public:
- database() = default;
- explicit database(environment& env) : odbc::base_database(env)
- {
- }
- database(database&& src) : odbc::base_database(std::move(src))
- {
- }
+ protected:
+ bool m_opened;
+ std::string m_connection;
- void open(const char* server_name, size_t server_name_length,
- const char* user_name, size_t user_name_length, const char* password, size_t password_length)
- {
- if (m_opened) close();
- verify_error(SQLConnectA(m_handle, (SQLCHAR*)server_name, static_cast<SQLSMALLINT>(server_name_length),
- (SQLCHAR*)user_name, static_cast<SQLSMALLINT>(user_name_length), (SQLCHAR*)password, static_cast<SQLSMALLINT>(password_length)));
- m_opened = true;
- }
- void open(const char* server_name, const char* user_name, const char* password)
- {
- verify_error(SQLConnectA(m_handle, (SQLCHAR*)server_name, SQL_NTS, (SQLCHAR*)user_name, SQL_NTS, (SQLCHAR*)password, SQL_NTS));
- }
- void open(const std::string& server_name, const std::string& user_name, const std::string& password)
- {
- open(server_name.data(), server_name.size(), user_name.data(), user_name.size(), password.data(), password.size());
- }
- void open(const char* input_text, size_t text_length = SQL_NTS, SQLSMALLINT driver_completion = SQL_DRIVER_NOPROMPT, SQLHWND hwnd = NULL)
- {
- m_connection.resize(512);
- SQLSMALLINT out_len=0;
- if (m_opened) close();
- verify_error(SQLDriverConnectA(m_handle, hwnd, (SQLCHAR*)input_text, (SQLSMALLINT)text_length,
- (SQLCHAR*)m_connection.data(), (SQLSMALLINT)m_connection.size(), &out_len, driver_completion));
- m_connection.resize(out_len);
- m_opened = true;
- }
- void open(const std::string& input_text, SQLSMALLINT driver_completion = SQL_DRIVER_NOPROMPT, SQLHWND hwnd = NULL)
- {
- open(input_text.data(), input_text.size(), driver_completion, hwnd);
- }
- void open(SQLHWND hwnd, SQLSMALLINT driver_completion = SQL_DRIVER_COMPLETE)
- {
- open("", SQL_NTS, driver_completion, hwnd);
- }
- // InputPred like:
- // bool input_parameters(connection_parameters& parameters);
- template<typename InputPred>
- void open(const char* connection_text, size_t text_length, InputPred&& pred)
- {
- SQLSMALLINT length = 0;
- SQLRETURN ret = SQL_SUCCESS;
- std::string input_text;
- if (m_opened) close();
- if (text_length == SQL_NTS)
- input_text = connection_text;
- else
- input_text.assign(connection_text, text_length);
- m_connection.resize(1024);
- while ((ret = SQLBrowseConnectA(m_handle, (SQLCHAR*)input_text.data(), SQL_NTS,
- (SQLCHAR*)m_connection.data(), m_connection.size(), &length)) == SQL_NEED_DATA)
+ void parse_browse_string(const char *output_text, size_t text_length, connection_parameters ¶meters);
+ std::string create_connection_text(const connection_parameters ¶meters);
+ };
+
+ class database : public base_database, public qtl::base_database<database, statement>
{
- connection_parameters parameters;
- parse_browse_string(m_connection.data(), length, parameters);
- if (!pred(parameters))
- throw error(SQL_NEED_DATA, "User cancel operation.");
- input_text = create_connection_text(parameters);
- }
- if (ret == SQL_ERROR || ret == SQL_SUCCESS_WITH_INFO)
- verify_error(ret);
- m_opened = true;
- }
- template<typename InputPred>
- void open(const char* connection_text, InputPred&& pred)
- {
- open(connection_text, SQL_NTS, std::forward<InputPred>(pred));
- }
- template<typename InputPred>
- void open(const std::string& connection_text, InputPred&& pred)
- {
- open(connection_text.data(), connection_text.size(), std::forward<InputPred>(pred));
- }
+ public:
+ database() = default;
+ explicit database(environment &env) : odbc::base_database(env)
+ {
+ }
+ database(database &&src) : odbc::base_database(std::move(src))
+ {
+ }
- statement open_command(const char* query_text, size_t text_length)
- {
- statement stmt(*this);
- stmt.open(query_text, text_length);
- return stmt;
- }
- statement open_command(const char* query_text)
- {
- return open_command(query_text, strlen(query_text));
- }
- statement open_command(const std::string& query_text)
- {
- return open_command(query_text.data(), query_text.length());
- }
+ void open(const char *server_name, size_t server_name_length,
+ const char *user_name, size_t user_name_length, const char *password, size_t password_length)
+ {
+ if (m_opened)
+ close();
+ verify_error(SQLConnectA(m_handle, (SQLCHAR *)server_name, static_cast<SQLSMALLINT>(server_name_length),
+ (SQLCHAR *)user_name, static_cast<SQLSMALLINT>(user_name_length), (SQLCHAR *)password, static_cast<SQLSMALLINT>(password_length)));
+ m_opened = true;
+ }
+ void open(const char *server_name, const char *user_name, const char *password)
+ {
+ verify_error(SQLConnectA(m_handle, (SQLCHAR *)server_name, SQL_NTS, (SQLCHAR *)user_name, SQL_NTS, (SQLCHAR *)password, SQL_NTS));
+ }
+ void open(const std::string &server_name, const std::string &user_name, const std::string &password)
+ {
+ open(server_name.data(), server_name.size(), user_name.data(), user_name.size(), password.data(), password.size());
+ }
+ void open(const char *input_text, size_t text_length = SQL_NTS, SQLSMALLINT driver_completion = SQL_DRIVER_NOPROMPT, SQLHWND hwnd = NULL)
+ {
+ m_connection.resize(512);
+ SQLSMALLINT out_len = 0;
+ if (m_opened)
+ close();
+ verify_error(SQLDriverConnectA(m_handle, hwnd, (SQLCHAR *)input_text, (SQLSMALLINT)text_length,
+ (SQLCHAR *)m_connection.data(), (SQLSMALLINT)m_connection.size(), &out_len, driver_completion));
+ m_connection.resize(out_len);
+ m_opened = true;
+ }
+ void open(const std::string &input_text, SQLSMALLINT driver_completion = SQL_DRIVER_NOPROMPT, SQLHWND hwnd = NULL)
+ {
+ open(input_text.data(), input_text.size(), driver_completion, hwnd);
+ }
+ void open(SQLHWND hwnd, SQLSMALLINT driver_completion = SQL_DRIVER_COMPLETE)
+ {
+ open("", SQL_NTS, driver_completion, hwnd);
+ }
+ // InputPred like:
+ // bool input_parameters(connection_parameters& parameters);
+ template <typename InputPred>
+ void open(const char *connection_text, size_t text_length, InputPred &&pred)
+ {
+ SQLSMALLINT length = 0;
+ SQLRETURN ret = SQL_SUCCESS;
+ std::string input_text;
+ if (m_opened)
+ close();
+ if (text_length == SQL_NTS)
+ input_text = connection_text;
+ else
+ input_text.assign(connection_text, text_length);
+ m_connection.resize(1024);
+ while ((ret = SQLBrowseConnectA(m_handle, (SQLCHAR *)input_text.data(), SQL_NTS,
+ (SQLCHAR *)m_connection.data(), m_connection.size(), &length)) == SQL_NEED_DATA)
+ {
+ connection_parameters parameters;
+ parse_browse_string(m_connection.data(), length, parameters);
+ if (!pred(parameters))
+ throw error(SQL_NEED_DATA, "User cancel operation.");
+ input_text = create_connection_text(parameters);
+ }
+ if (ret == SQL_ERROR || ret == SQL_SUCCESS_WITH_INFO)
+ verify_error(ret);
+ m_opened = true;
+ }
+ template <typename InputPred>
+ void open(const char *connection_text, InputPred &&pred)
+ {
+ open(connection_text, SQL_NTS, std::forward<InputPred>(pred));
+ }
+ template <typename InputPred>
+ void open(const std::string &connection_text, InputPred &&pred)
+ {
+ open(connection_text.data(), connection_text.size(), std::forward<InputPred>(pred));
+ }
- void simple_execute(const char* query_text, size_t text_length = SQL_NTS)
- {
- statement command(*this);
- SQLRETURN ret = SQLExecDirectA(command.handle(), (SQLCHAR*)query_text, text_length);
- if (ret != SQL_SUCCESS && ret != SQL_NO_DATA)
- verify_error(ret);
- }
- void simple_execute(const std::string& query_text)
- {
- simple_execute(query_text.data(), query_text.size());
- }
+ statement open_command(const char *query_text, size_t text_length)
+ {
+ statement stmt(*this);
+ stmt.open(query_text, text_length);
+ return stmt;
+ }
+ statement open_command(const char *query_text)
+ {
+ return open_command(query_text, strlen(query_text));
+ }
+ statement open_command(const std::string &query_text)
+ {
+ return open_command(query_text.data(), query_text.length());
+ }
- void auto_commit(bool on)
- {
- set_attribute(SQL_ATTR_AUTOCOMMIT, on ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF);
- }
- void begin_transaction()
- {
- auto_commit(false);
- }
- void rollback()
- {
- verify_error(SQLEndTran(handler_type, m_handle, SQL_ROLLBACK));
- auto_commit(true);
- }
- void commit()
- {
- verify_error(SQLEndTran(handler_type, m_handle, SQL_COMMIT));
- auto_commit(true);
- }
+ void simple_execute(const char *query_text, size_t text_length = SQL_NTS)
+ {
+ statement command(*this);
+ SQLRETURN ret = SQLExecDirectA(command.handle(), (SQLCHAR *)query_text, text_length);
+ if (ret != SQL_SUCCESS && ret != SQL_NO_DATA)
+ verify_error(ret);
+ }
+ void simple_execute(const std::string &query_text)
+ {
+ simple_execute(query_text.data(), query_text.size());
+ }
- bool is_alive()
- {
- SQLINTEGER value;
- get_attribute(SQL_ATTR_CONNECTION_DEAD, value);
- return value == SQL_CD_FALSE;
- }
+ void auto_commit(bool on)
+ {
+ set_attribute(SQL_ATTR_AUTOCOMMIT, on ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF);
+ }
+ void begin_transaction()
+ {
+ auto_commit(false);
+ }
+ void rollback()
+ {
+ verify_error(SQLEndTran(handler_type, m_handle, SQL_ROLLBACK));
+ auto_commit(true);
+ }
+ void commit()
+ {
+ verify_error(SQLEndTran(handler_type, m_handle, SQL_COMMIT));
+ auto_commit(true);
+ }
+
+ bool is_alive()
+ {
+ SQLINTEGER value;
+ get_attribute(SQL_ATTR_CONNECTION_DEAD, value);
+ return value == SQL_CD_FALSE;
+ }
#ifdef QTL_ODBC_ENABLE_ASYNC_MODE
- //async_connection async_mode();
+ // async_connection async_mode();
-#endif //ODBC 3.80
+#endif // ODBC 3.80
+ };
-};
+ struct date : public SQL_DATE_STRUCT
+ {
+ date()
+ {
+ memset(this, 0, sizeof(SQL_DATE_STRUCT));
+ }
+ };
-struct date : public SQL_DATE_STRUCT
-{
- date()
- {
- memset(this, 0, sizeof(SQL_DATE_STRUCT));
- }
-};
+ struct time : public SQL_TIME_STRUCT
+ {
+ time()
+ {
+ memset(this, 0, sizeof(SQL_TIME_STRUCT));
+ }
+ };
-struct time : public SQL_TIME_STRUCT
-{
- time()
- {
- memset(this, 0, sizeof(SQL_TIME_STRUCT));
- }
-};
-
-struct timestamp : public SQL_TIMESTAMP_STRUCT
-{
- timestamp()
- {
- memset(this, 0, sizeof(SQL_TIMESTAMP_STRUCT));
- }
- timestamp(struct tm& tm)
- {
- year=tm.tm_year+1900;
- month=tm.tm_mon+1;
- day=tm.tm_mday;
- hour=tm.tm_hour;
- minute=tm.tm_min;
- second=tm.tm_sec;
- }
- timestamp(time_t value)
- {
- struct tm tm;
+ struct timestamp : public SQL_TIMESTAMP_STRUCT
+ {
+ timestamp()
+ {
+ memset(this, 0, sizeof(SQL_TIMESTAMP_STRUCT));
+ }
+ timestamp(struct tm &tm)
+ {
+ year = tm.tm_year + 1900;
+ month = tm.tm_mon + 1;
+ day = tm.tm_mday;
+ hour = tm.tm_hour;
+ minute = tm.tm_min;
+ second = tm.tm_sec;
+ }
+ timestamp(time_t value)
+ {
+ struct tm tm;
#if defined(_MSC_VER)
- localtime_s(&tm, &value);
+ localtime_s(&tm, &value);
#elif defined(_POSIX_VERSION)
- localtime_r(&value, &tm);
+ localtime_r(&value, &tm);
#else
- tm=*localtime(&value);
+ tm = *localtime(&value);
#endif
- new(this)timestamp(tm);
- }
- timestamp(const timestamp& src)
- {
- memcpy(this, &src, sizeof(SQL_TIMESTAMP_STRUCT));
- }
- timestamp& operator=(const timestamp& src)
- {
- if(this!=&src)
- memcpy(this, &src, sizeof(SQL_TIMESTAMP_STRUCT));
- return *this;
- }
+ new (this) timestamp(tm);
+ }
+ timestamp(const timestamp &src)
+ {
+ memcpy(this, &src, sizeof(SQL_TIMESTAMP_STRUCT));
+ }
+ timestamp &operator=(const timestamp &src)
+ {
+ if (this != &src)
+ memcpy(this, &src, sizeof(SQL_TIMESTAMP_STRUCT));
+ return *this;
+ }
- static timestamp now()
- {
- time_t value;
- ::time(&value);
- return timestamp(value);
- }
+ static timestamp now()
+ {
+ time_t value;
+ ::time(&value);
+ return timestamp(value);
+ }
- time_t as_tm(struct tm& tm) const
- {
- tm.tm_year=year-1900;
- tm.tm_mon=month-1;
- tm.tm_mday=day;
- tm.tm_hour=hour;
- tm.tm_min=minute;
- tm.tm_sec=second;
- return mktime(&tm);
- }
- time_t get_time() const
- {
- struct tm tm;
- return as_tm(tm);
- }
- timeval get_timeval() const
- {
- timeval tv;
- struct tm tm;
- tv.tv_sec=as_tm(tm);
- tv.tv_usec=fraction/1000;
- }
-};
+ time_t as_tm(struct tm &tm) const
+ {
+ tm.tm_year = year - 1900;
+ tm.tm_mon = month - 1;
+ tm.tm_mday = day;
+ tm.tm_hour = hour;
+ tm.tm_min = minute;
+ tm.tm_sec = second;
+ return mktime(&tm);
+ }
+ time_t get_time() const
+ {
+ struct tm tm;
+ return as_tm(tm);
+ }
+ timeval get_timeval() const
+ {
+ timeval tv;
+ struct tm tm;
+ tv.tv_sec = as_tm(tm);
+ tv.tv_usec = fraction / 1000;
+ }
+ };
#ifdef QTL_ODBC_ENABLE_ASYNC_MODE
-class async_connection;
+ class async_connection;
-inline bool is_still_executing(SQLINTEGER code)
-{
- return code == SQL_STILL_EXECUTING;
-}
-
-class async_statement : public base_statement
-{
-public:
- explicit async_statement(async_connection& db);
- async_statement(async_statement&& src)
- : base_statement(std::move(src))
- {
- m_hCompleteEvent = src.m_hCompleteEvent;
- m_event=src.m_event;
- m_nQueryTimeout = src.m_nQueryTimeout;
- src.m_hCompleteEvent = nullptr;
- src.m_event = nullptr;
- }
- async_statement& operator=(async_statement&& src)
- {
- if (this != &src)
+ inline bool is_still_executing(SQLINTEGER code)
{
- base_statement::operator =(std::move(src));
- m_hCompleteEvent = src.m_hCompleteEvent;
- m_event = src.m_event;
- m_nQueryTimeout = src.m_nQueryTimeout;
- src.m_hCompleteEvent = nullptr;
- src.m_event = nullptr;
- }
- return *this;
- }
- ~async_statement()
- {
- close();
- }
-
- /*
- Handler defiens as:
- void handler(const qtl::odbc::error& e);
- */
- template<typename Handler>
- void open(Handler&& handler, const char *query_text, size_t text_length = 0)
- {
- if (text_length == 0) text_length = strlen(query_text);
- reset();
- SQLRETURN ret = SQLPrepareA(m_handle, (SQLCHAR*)query_text, text_length);
- async_wait(ret, std::forward<Handler>(handler));
- }
-
- /*
- ExecuteHandler defiens as:
- void handler(const qtl::odbc::error& e, uint64_t affected);
- */
- template<typename Types, typename Handler>
- void execute(const Types& params, Handler&& handler)
- {
- SQLSMALLINT count = 0;
- SQLRETURN ret = SQLNumParams(m_handle, &count);
- if (!SQL_SUCCEEDED(ret))
- {
- handler(error(*this, ret), 0);
- return;
- }
- if (count > 0)
- {
- m_params.resize(count);
- qtl::bind_params(*this, params);
+ return code == SQL_STILL_EXECUTING;
}
- if (m_nQueryTimeout == 0)
- m_nQueryTimeout = query_timeout();
- ret = SQLExecute(m_handle);
- async_wait(ret, [this, count, handler](const error& e) mutable {
+ class async_statement : public base_statement
+ {
+ public:
+ explicit async_statement(async_connection &db);
+ async_statement(async_statement &&src)
+ : base_statement(std::move(src))
+ {
+ m_hCompleteEvent = src.m_hCompleteEvent;
+ m_event = src.m_event;
+ m_nQueryTimeout = src.m_nQueryTimeout;
+ src.m_hCompleteEvent = nullptr;
+ src.m_event = nullptr;
+ }
+ async_statement &operator=(async_statement &&src)
+ {
+ if (this != &src)
+ {
+ base_statement::operator=(std::move(src));
+ m_hCompleteEvent = src.m_hCompleteEvent;
+ m_event = src.m_event;
+ m_nQueryTimeout = src.m_nQueryTimeout;
+ src.m_hCompleteEvent = nullptr;
+ src.m_event = nullptr;
+ }
+ return *this;
+ }
+ ~async_statement()
+ {
+ close();
+ }
+
+ /*
+ Handler defiens as:
+ void handler(const qtl::odbc::error& e);
+ */
+ template <typename Handler>
+ void open(Handler &&handler, const char *query_text, size_t text_length = 0)
+ {
+ if (text_length == 0)
+ text_length = strlen(query_text);
+ reset();
+ SQLRETURN ret = SQLPrepareA(m_handle, (SQLCHAR *)query_text, text_length);
+ async_wait(ret, std::forward<Handler>(handler));
+ }
+
+ /*
+ ExecuteHandler defiens as:
+ void handler(const qtl::odbc::error& e, uint64_t affected);
+ */
+ template <typename Types, typename Handler>
+ void execute(const Types ¶ms, Handler &&handler)
+ {
+ SQLSMALLINT count = 0;
+ SQLRETURN ret = SQLNumParams(m_handle, &count);
+ if (!SQL_SUCCEEDED(ret))
+ {
+ handler(error(*this, ret), 0);
+ return;
+ }
+ if (count > 0)
+ {
+ m_params.resize(count);
+ qtl::bind_params(*this, params);
+ }
+
+ if (m_nQueryTimeout == 0)
+ m_nQueryTimeout = query_timeout();
+ ret = SQLExecute(m_handle);
+ async_wait(ret, [this, count, handler](const error &e) mutable
+ {
SQLINTEGER ret = e.code();
if (ret == SQL_NEED_DATA)
async_param_data(0, count, std::forward<Handler>(handler));
else if(ret>=0)
handler(error(*this, ret), affetced_rows());
else
- handler(error(*this, ret), 0);
- });
- }
-
- template<typename Types, typename RowHandler, typename FinishHandler>
- void fetch(Types&& values, RowHandler&& row_handler, FinishHandler&& finish_handler)
- {
- if (!m_binded_cols)
- {
- SQLSMALLINT count = 0;
- SQLRETURN ret = SQLNumResultCols(m_handle, &count);
- if(!SQL_SUCCEEDED(ret))
- {
- finish_handler(error(*this, ret));
- return;
+ handler(error(*this, ret), 0); });
}
- if (count > 0)
+
+ template <typename Types, typename RowHandler, typename FinishHandler>
+ void fetch(Types &&values, RowHandler &&row_handler, FinishHandler &&finish_handler)
{
- m_params.resize(count);
- qtl::bind_record(*this, std::forward<Types>(values));
+ if (!m_binded_cols)
+ {
+ SQLSMALLINT count = 0;
+ SQLRETURN ret = SQLNumResultCols(m_handle, &count);
+ if (!SQL_SUCCEEDED(ret))
+ {
+ finish_handler(error(*this, ret));
+ return;
+ }
+ if (count > 0)
+ {
+ m_params.resize(count);
+ qtl::bind_record(*this, std::forward<Types>(values));
+ }
+ m_binded_cols = true;
+ }
+ return fetch(std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
}
- m_binded_cols = true;
- }
- return fetch(std::forward<RowHandler>(row_handler), std::forward<FinishHandler>(finish_handler));
- }
- template<typename RowHandler, typename FinishHandler>
- void fetch(RowHandler&& row_handler, FinishHandler&& finish_handler)
- {
- SQLRETURN ret = SQLFetch(m_handle);
- async_wait(ret, [this, row_handler, finish_handler](const error& e) mutable {
+ template <typename RowHandler, typename FinishHandler>
+ void fetch(RowHandler &&row_handler, FinishHandler &&finish_handler)
+ {
+ SQLRETURN ret = SQLFetch(m_handle);
+ async_wait(ret, [this, row_handler, finish_handler](const error &e) mutable
+ {
SQLINTEGER ret = e.code();
if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
{
@@ -1383,17 +1404,17 @@
finish_handler(error());
else
finish_handler(e);
+ } });
}
- });
- }
- template<typename Handler>
- void next_result(Handler handler)
- {
- SQLRETURN ret;
- m_binded_cols = false;
- ret = SQLMoreResults(m_handle);
- async_wait(ret, [this, handler](const error& e) mutable {
+ template <typename Handler>
+ void next_result(Handler handler)
+ {
+ SQLRETURN ret;
+ m_binded_cols = false;
+ ret = SQLMoreResults(m_handle);
+ async_wait(ret, [this, handler](const error &e) mutable
+ {
SQLINTEGER ret=e.code();
SQLSMALLINT count = 0;
if (ret == SQL_ERROR || ret == SQL_INVALID_HANDLE)
@@ -1412,83 +1433,83 @@
if (count > 0)
handler(error());
else
- next_result(handler);
- });
- }
+ next_result(handler); });
+ }
- HANDLE event_handle() const { return m_hCompleteEvent; }
+ HANDLE event_handle() const { return m_hCompleteEvent; }
- void close()
- {
- close_event();
- base_statement::close();
- }
+ void close()
+ {
+ close_event();
+ base_statement::close();
+ }
- template<typename CloseHandler>
- void close(CloseHandler&& handler)
- {
- if (m_handle)
- {
- close_event();
- SQLRETURN ret = SQLFreeHandle(handler_type, m_handle);
- if(SQL_SUCCEEDED(ret))
- m_handle = SQL_NULL_HANDLE;
- handler(error(*this, ret));
- }
- else
- {
- handler(error());
- }
- }
+ template <typename CloseHandler>
+ void close(CloseHandler &&handler)
+ {
+ if (m_handle)
+ {
+ close_event();
+ SQLRETURN ret = SQLFreeHandle(handler_type, m_handle);
+ if (SQL_SUCCEEDED(ret))
+ m_handle = SQL_NULL_HANDLE;
+ handler(error(*this, ret));
+ }
+ else
+ {
+ handler(error());
+ }
+ }
-private:
+ private:
+ void close_event()
+ {
+ if (m_hCompleteEvent)
+ {
+ if (m_event)
+ m_event->remove();
+ verify_error(SQLCancelHandle(handler_type, m_handle));
+ verify_error(SQLSetStmtAttr(m_handle, SQL_ATTR_ASYNC_STMT_EVENT, NULL, SQL_IS_POINTER));
+ verify_error(SQLSetStmtAttr(m_handle, SQL_ATTR_ASYNC_ENABLE, (SQLPOINTER)SQL_ASYNC_ENABLE_OFF, SQL_IS_INTEGER));
+ CloseHandle(m_hCompleteEvent);
+ m_hCompleteEvent = NULL;
+ }
+ }
- void close_event()
- {
- if (m_hCompleteEvent)
- {
- if (m_event)
- m_event->remove();
- verify_error(SQLCancelHandle(handler_type, m_handle));
- verify_error(SQLSetStmtAttr(m_handle, SQL_ATTR_ASYNC_STMT_EVENT, NULL, SQL_IS_POINTER));
- verify_error(SQLSetStmtAttr(m_handle, SQL_ATTR_ASYNC_ENABLE, (SQLPOINTER)SQL_ASYNC_ENABLE_OFF, SQL_IS_INTEGER));
- CloseHandle(m_hCompleteEvent);
- m_hCompleteEvent = NULL;
- }
- }
+ template <typename Handler>
+ void async_wait(SQLINTEGER ret, Handler &&handler) NOEXCEPT
+ {
+ if (is_still_executing(ret))
+ {
+ m_event->set_io_handler(0, m_nQueryTimeout,
+ [this, handler](int flags) mutable
+ {
+ RETCODE code;
+ SQLCompleteAsync(SQL_HANDLE_STMT, m_handle, &code);
+ if (SQL_SUCCEEDED(code))
+ {
+ handler(odbc::error());
+ }
+ else
+ {
+ SetEvent(m_hCompleteEvent);
+ handler(odbc::error(*this, code));
+ }
+ });
+ }
+ else
+ {
+ handler(error(*this, ret));
+ }
+ }
- template<typename Handler>
- void async_wait(SQLINTEGER ret, Handler&& handler) NOEXCEPT
- {
- if(is_still_executing(ret))
- {
- m_event->set_io_handler(0, m_nQueryTimeout,
- [this, handler](int flags) mutable {
- RETCODE code;
- SQLCompleteAsync(SQL_HANDLE_STMT, m_handle, &code);
- if (SQL_SUCCEEDED(code))
- {
- handler(odbc::error());
- }
- else
- {
- SetEvent(m_hCompleteEvent);
- handler(odbc::error(*this, code));
- }
- });
- }
- else
- {
- handler(error(*this, ret));
- }
- }
-
- template<typename Handler>
- void async_param_data(SQLSMALLINT index, SQLSMALLINT count, Handler&& handler) NOEXCEPT
- {
- SQLPOINTER token;
- SQLRETURN ret = SQLParamData(m_handle, &token);
- async_wait(ret, [this, index, count, token, handler](const error& e) mutable {
+ template <typename Handler>
+ void async_param_data(SQLSMALLINT index, SQLSMALLINT count, Handler &&handler) NOEXCEPT
+ {
+ SQLPOINTER token;
+ SQLRETURN ret = SQLParamData(m_handle, &token);
+ async_wait(ret, [this, index, count, token, handler](const error &e) mutable
+ {
SQLINTEGER ret = e.code();
if (ret == SQL_NEED_DATA)
{
@@ -1507,430 +1528,440 @@
else
{
handler(error(*this, ret), affetced_rows());
+ } });
}
- });
- }
- int query_timeout() const
- {
- SQLULEN timeout = 0;
- verify_error(SQLGetStmtAttr(m_handle, SQL_ATTR_QUERY_TIMEOUT, (SQLPOINTER)&timeout, NULL, NULL));
- return timeout;
- }
+ int query_timeout() const
+ {
+ SQLULEN timeout = 0;
+ verify_error(SQLGetStmtAttr(m_handle, SQL_ATTR_QUERY_TIMEOUT, (SQLPOINTER)&timeout, NULL, NULL));
+ return timeout;
+ }
-private:
- HANDLE m_hCompleteEvent;
- qtl::event* m_event;
- SQLULEN m_nQueryTimeout;
-};
+ private:
+ HANDLE m_hCompleteEvent;
+ qtl::event *m_event;
+ SQLULEN m_nQueryTimeout;
+ };
-class async_connection : public base_database, public qtl::async_connection<async_connection, async_statement>
-{
-public:
- async_connection(environment& env) : base_database(env)
- {
- set_attribute(SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE, SQL_ASYNC_DBC_ENABLE_ON);
- m_hCompleteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (m_hCompleteEvent == NULL)
+ class async_connection : public base_database, public qtl::async_connection<async_connection, async_statement>
{
- throw std::system_error(std::error_code(GetLastError(), std::system_category()));
- }
- set_attribute(SQL_ATTR_ASYNC_DBC_EVENT, m_hCompleteEvent);
- }
- async_connection(async_connection&& src) :
- base_database(std::move(src)),
- qtl::async_connection<async_connection, async_statement>(std::move(src)),
- m_BindFunc(std::move(src.m_BindFunc))
- {
- m_hCompleteEvent = src.m_hCompleteEvent;
- src.m_hCompleteEvent = nullptr;
- }
- ~async_connection()
- {
- if (m_hCompleteEvent)
- {
- verify_error(SQLCancelHandle(handler_type, m_handle));
- set_attribute(SQL_ATTR_ASYNC_DBC_EVENT, (SQLPOINTER)NULL);
- }
- if (m_opened)
- {
- set_attribute(SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE, SQL_ASYNC_DBC_ENABLE_OFF);
- verify_error(SQLDisconnect(m_handle));
- m_opened = false;
- }
- if (m_hCompleteEvent)
- {
- CloseHandle(m_hCompleteEvent);
- }
- }
-
- /*
- OpenHandler defines as:
- void handler(const qtl::odbc::error& e) NOEXCEPT;
- */
- template<class EventLoop, typename OpenHandler>
- void open(EventLoop& ev, OpenHandler&& handler, const char* server_name, size_t server_name_length,
- const char* user_name, size_t user_name_length, const char* password, size_t password_length)
- {
- if (m_opened) close();
- SQLRETURN err = SQLConnectA(m_handle, (SQLCHAR*)server_name, static_cast<SQLSMALLINT>(server_name_length),
- (SQLCHAR*)user_name, static_cast<SQLSMALLINT>(user_name_length), (SQLCHAR*)password, static_cast<SQLSMALLINT>(password_length));
- async_wait_connect(err, ev, std::forward<OpenHandler>(handler));
- }
- template<class EventLoop, typename OpenHandler>
- void open(EventLoop& ev, OpenHandler&& handler, const char* server_name, const char* user_name, const char* password)
- {
- if (m_opened) close();
- SQLRETURN err = SQLConnectA(m_handle, (SQLCHAR*)server_name, SQL_NTS, (SQLCHAR*)user_name, SQL_NTS, (SQLCHAR*)password, SQL_NTS);
- async_wait_connect(err, ev, std::forward<OpenHandler>(handler));
- }
- template<class EventLoop, typename OpenHandler>
- void open(EventLoop& ev, OpenHandler&& handler, const std::string& server_name, const std::string& user_name, const std::string& password)
- {
- open(ev, std::forward<OpenHandler>(handler), server_name.data(), server_name.size(), user_name.data(), user_name.size(), password.data(), password.size());
- }
- template<class EventLoop, typename OpenHandler>
- void open(EventLoop& ev, OpenHandler&& handler, const char* input_text, size_t text_length = SQL_NTS, SQLSMALLINT driver_completion = SQL_DRIVER_NOPROMPT, SQLHWND hwnd = NULL)
- {
- m_connection.resize(512);
- SQLSMALLINT out_len=0;
- SQLRETURN err = SQLDriverConnectA(m_handle, hwnd, (SQLCHAR*)input_text, (SQLSMALLINT)text_length,
- (SQLCHAR*)m_connection.data(), (SQLSMALLINT)m_connection.size(), &out_len, driver_completion);
- m_connection.resize(out_len);
- async_wait_connect(err, ev, std::forward<OpenHandler>(handler));
- }
- template<class EventLoop, typename OpenHandler>
- void open(EventLoop& ev, OpenHandler&& handler, const std::string& input_text, SQLSMALLINT driver_completion = SQL_DRIVER_NOPROMPT, SQLHWND hwnd = NULL)
- {
- open(ev, std::forward<OpenHandler>(handler), input_text.data(), input_text.size(), driver_completion, hwnd);
- }
- template<class EventLoop, typename OpenHandler>
- void open(EventLoop& ev, OpenHandler&& handler, SQLHWND hwnd, SQLSMALLINT driver_completion = SQL_DRIVER_COMPLETE)
- {
- open(ev, std::forward<OpenHandler>(handler), "", SQL_NTS, driver_completion, hwnd);
- }
-
- /*
- CloseHandler defines as:
- void handler(const qtl::odbc::error& e) NOEXCEPT;
- */
- template<typename CloseHandler >
- void close(CloseHandler&& handler) NOEXCEPT
- {
- SQLRETURN ret = SQLDisconnect(m_handle);
- m_opened = false;
- async_wait(ret, [this, handler](const error& e) {
- if (!e) m_opened = false;
- handler(e);
- });
- }
-
- /*
- ExecuteHandler defines as:
- void handler(const qtl::odbc::error& e) NOEXCEPT;
- */
- template<typename ExecuteHandler>
- void simple_execute(ExecuteHandler&& handler, const char* query_text, size_t text_length = SQL_NTS) NOEXCEPT
- {
- statement command(*this);
- SQLRETURN ret = SQLExecDirectA(command.handle(), (SQLCHAR*)query_text, static_cast<SQLINTEGER>(text_length));
- async_wait(ret, std::forward<ExecuteHandler>(handler));
- }
- template<typename ExecuteHandler>
- void simple_execute(ExecuteHandler&& handler, const std::string& query_text)
- {
- simple_execute(std::forward<ExecuteHandler>(handler), query_text.data(), query_text.size());
- }
-
- template<typename Handler>
- void open_command(const char* query_text, size_t text_length, Handler&& handler)
- {
- std::shared_ptr<async_statement> stmt = std::make_shared<async_statement>(*this);
- stmt->open([stmt, handler](const odbc::error& e) mutable {
- handler(e, stmt);
- }, query_text, text_length);
- }
-
- HANDLE event_handle() const { return m_hCompleteEvent; }
-
- qtl::event* rebind(HANDLE hEvent)
- {
- return m_BindFunc(hEvent);
- }
-
-private:
-
- template<typename Handler>
- void async_wait(SQLRETURN ret, Handler&& handler) NOEXCEPT
- {
- if (is_still_executing(ret))
- {
- m_event_handler->set_io_handler(0, connect_timeout(),
- [this, handler](int flags) mutable {
- RETCODE code;
- SQLCompleteAsync(SQL_HANDLE_DBC, m_handle, &code);
- if (SQL_SUCCEEDED(code))
+ public:
+ async_connection(environment &env) : base_database(env)
+ {
+ set_attribute(SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE, SQL_ASYNC_DBC_ENABLE_ON);
+ m_hCompleteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (m_hCompleteEvent == NULL)
{
- handler(odbc::error());
+ throw std::system_error(std::error_code(GetLastError(), std::system_category()));
+ }
+ set_attribute(SQL_ATTR_ASYNC_DBC_EVENT, m_hCompleteEvent);
+ }
+ async_connection(async_connection &&src) : base_database(std::move(src)),
+ qtl::async_connection<async_connection, async_statement>(std::move(src)),
+ m_BindFunc(std::move(src.m_BindFunc))
+ {
+ m_hCompleteEvent = src.m_hCompleteEvent;
+ src.m_hCompleteEvent = nullptr;
+ }
+ ~async_connection()
+ {
+ if (m_hCompleteEvent)
+ {
+ verify_error(SQLCancelHandle(handler_type, m_handle));
+ set_attribute(SQL_ATTR_ASYNC_DBC_EVENT, (SQLPOINTER)NULL);
+ }
+ if (m_opened)
+ {
+ set_attribute(SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE, SQL_ASYNC_DBC_ENABLE_OFF);
+ verify_error(SQLDisconnect(m_handle));
+ m_opened = false;
+ }
+ if (m_hCompleteEvent)
+ {
+ CloseHandle(m_hCompleteEvent);
+ }
+ }
+
+ /*
+ OpenHandler defines as:
+ void handler(const qtl::odbc::error& e) NOEXCEPT;
+ */
+ template <class EventLoop, typename OpenHandler>
+ void open(EventLoop &ev, OpenHandler &&handler, const char *server_name, size_t server_name_length,
+ const char *user_name, size_t user_name_length, const char *password, size_t password_length)
+ {
+ if (m_opened)
+ close();
+ SQLRETURN err = SQLConnectA(m_handle, (SQLCHAR *)server_name, static_cast<SQLSMALLINT>(server_name_length),
+ (SQLCHAR *)user_name, static_cast<SQLSMALLINT>(user_name_length), (SQLCHAR *)password, static_cast<SQLSMALLINT>(password_length));
+ async_wait_connect(err, ev, std::forward<OpenHandler>(handler));
+ }
+ template <class EventLoop, typename OpenHandler>
+ void open(EventLoop &ev, OpenHandler &&handler, const char *server_name, const char *user_name, const char *password)
+ {
+ if (m_opened)
+ close();
+ SQLRETURN err = SQLConnectA(m_handle, (SQLCHAR *)server_name, SQL_NTS, (SQLCHAR *)user_name, SQL_NTS, (SQLCHAR *)password, SQL_NTS);
+ async_wait_connect(err, ev, std::forward<OpenHandler>(handler));
+ }
+ template <class EventLoop, typename OpenHandler>
+ void open(EventLoop &ev, OpenHandler &&handler, const std::string &server_name, const std::string &user_name, const std::string &password)
+ {
+ open(ev, std::forward<OpenHandler>(handler), server_name.data(), server_name.size(), user_name.data(), user_name.size(), password.data(), password.size());
+ }
+ template <class EventLoop, typename OpenHandler>
+ void open(EventLoop &ev, OpenHandler &&handler, const char *input_text, size_t text_length = SQL_NTS, SQLSMALLINT driver_completion = SQL_DRIVER_NOPROMPT, SQLHWND hwnd = NULL)
+ {
+ m_connection.resize(512);
+ SQLSMALLINT out_len = 0;
+ SQLRETURN err = SQLDriverConnectA(m_handle, hwnd, (SQLCHAR *)input_text, (SQLSMALLINT)text_length,
+ (SQLCHAR *)m_connection.data(), (SQLSMALLINT)m_connection.size(), &out_len, driver_completion);
+ m_connection.resize(out_len);
+ async_wait_connect(err, ev, std::forward<OpenHandler>(handler));
+ }
+ template <class EventLoop, typename OpenHandler>
+ void open(EventLoop &ev, OpenHandler &&handler, const std::string &input_text, SQLSMALLINT driver_completion = SQL_DRIVER_NOPROMPT, SQLHWND hwnd = NULL)
+ {
+ open(ev, std::forward<OpenHandler>(handler), input_text.data(), input_text.size(), driver_completion, hwnd);
+ }
+ template <class EventLoop, typename OpenHandler>
+ void open(EventLoop &ev, OpenHandler &&handler, SQLHWND hwnd, SQLSMALLINT driver_completion = SQL_DRIVER_COMPLETE)
+ {
+ open(ev, std::forward<OpenHandler>(handler), "", SQL_NTS, driver_completion, hwnd);
+ }
+
+ /*
+ CloseHandler defines as:
+ void handler(const qtl::odbc::error& e) NOEXCEPT;
+ */
+ template <typename CloseHandler>
+ void close(CloseHandler &&handler) NOEXCEPT
+ {
+ SQLRETURN ret = SQLDisconnect(m_handle);
+ m_opened = false;
+ async_wait(ret, [this, handler](const error &e)
+ {
+ if (!e) m_opened = false;
+ handler(e); });
+ }
+
+ /*
+ ExecuteHandler defines as:
+ void handler(const qtl::odbc::error& e) NOEXCEPT;
+ */
+ template <typename ExecuteHandler>
+ void simple_execute(ExecuteHandler &&handler, const char *query_text, size_t text_length = SQL_NTS) NOEXCEPT
+ {
+ statement command(*this);
+ SQLRETURN ret = SQLExecDirectA(command.handle(), (SQLCHAR *)query_text, static_cast<SQLINTEGER>(text_length));
+ async_wait(ret, std::forward<ExecuteHandler>(handler));
+ }
+ template <typename ExecuteHandler>
+ void simple_execute(ExecuteHandler &&handler, const std::string &query_text)
+ {
+ simple_execute(std::forward<ExecuteHandler>(handler), query_text.data(), query_text.size());
+ }
+
+ template <typename Handler>
+ void open_command(const char *query_text, size_t text_length, Handler &&handler)
+ {
+ std::shared_ptr<async_statement> stmt = std::make_shared<async_statement>(*this);
+ stmt->open([stmt, handler](const odbc::error &e) mutable
+ { handler(e, stmt); }, query_text, text_length);
+ }
+
+ HANDLE event_handle() const { return m_hCompleteEvent; }
+
+ qtl::event *rebind(HANDLE hEvent)
+ {
+ return m_BindFunc(hEvent);
+ }
+
+ private:
+ template <typename Handler>
+ void async_wait(SQLRETURN ret, Handler &&handler) NOEXCEPT
+ {
+ if (is_still_executing(ret))
+ {
+ m_event_handler->set_io_handler(0, connect_timeout(),
+ [this, handler](int flags) mutable
+ {
+ RETCODE code;
+ SQLCompleteAsync(SQL_HANDLE_DBC, m_handle, &code);
+ if (SQL_SUCCEEDED(code))
+ {
+ handler(odbc::error());
+ }
+ else
+ {
+ SetEvent(m_hCompleteEvent);
+ handler(odbc::error(*this, code));
+ }
+ });
}
else
{
- SetEvent(m_hCompleteEvent);
- handler(odbc::error(*this, code));
+ handler(odbc::error(*this, ret));
}
- });
- }
- else
- {
- handler(odbc::error(*this, ret));
- }
- }
-
- template<typename EventLoop, typename Handler>
- void async_wait_connect(SQLRETURN err, EventLoop& ev, Handler&& handler)
- {
- bind(ev);
- m_BindFunc = [&ev](HANDLE hEvent) {
- return ev.add(hEvent);
- };
- if(is_still_executing(err))
- {
- async_wait(err, [this, handler](const error& e) mutable {
- if (!e) m_opened = true;
- handler(e);
- });
- }
- else
- {
- handler(odbc::error(*this, err));
- }
- }
-
- int connect_timeout() const
- {
- int timeout=0;
- verify_error(SQLGetConnectAttr(m_handle, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER)&timeout, 0, NULL));
- return timeout;
- }
-
-private:
- HANDLE m_hCompleteEvent;
- std::function<qtl::event*(HANDLE)> m_BindFunc;
-};
-
-inline async_statement::async_statement(async_connection& db)
- : base_statement(static_cast<base_database&>(db))
-{
- verify_error(SQLSetStmtAttr(m_handle, SQL_ATTR_ASYNC_ENABLE, (SQLPOINTER)SQL_ASYNC_ENABLE_ON, SQL_IS_INTEGER));
- m_hCompleteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (m_hCompleteEvent == NULL)
- {
- throw std::system_error(std::error_code(GetLastError(), std::system_category()));
- }
- verify_error(SQLSetStmtAttr(m_handle, SQL_ATTR_ASYNC_STMT_EVENT, m_hCompleteEvent, SQL_IS_POINTER));
- m_event = db.rebind(this->m_hCompleteEvent);
- m_nQueryTimeout = query_timeout();
-}
-
-#endif //ODBC 3.80
-
-typedef qtl::transaction<database> transaction;
-
-template<typename Record>
-using query_iterator = qtl::query_iterator<statement, Record>;
-
-template<typename Record>
-using query_result = qtl::query_result<statement, Record>;
-
-template<typename Params>
-inline statement& operator<<(statement& stmt, const Params& params)
-{
- stmt.reset();
- stmt.execute(params);
- return stmt;
-}
-
-template<SQLSMALLINT Type>
-inline error::error(const object<Type>& h, SQLINTEGER code)
-{
- m_errno=code;
- if(code==SQL_ERROR || code==SQL_SUCCESS_WITH_INFO)
- {
- SQLSMALLINT i=0;
- SQLINTEGER err=SQL_SUCCESS;
- SQLCHAR message[SQL_MAX_MESSAGE_LENGTH];
- SQLCHAR state[SQL_SQLSTATE_SIZE+1];
- std::ostringstream oss;
- SQLRETURN ret = SQLGetDiagRecA(object<Type>::handler_type, h.handle(), ++i, state, &err,
- message, SQL_MAX_MESSAGE_LENGTH, NULL);
- while(ret==SQL_SUCCESS)
- {
- oss<<"["<<state<<"] ("<<err<<") "<<message<<std::endl;
- ret = SQLGetDiagRecA(object<Type>::handler_type, h.handle(), ++i, state, &err,
- message, SQL_MAX_MESSAGE_LENGTH, NULL);
- }
- m_errmsg=oss.str();
- }
- else if(code==SQL_INVALID_HANDLE)
- {
- m_errmsg="Invalid handle.";
- }
-}
-
-inline void base_database::parse_browse_string(const char* output_text, size_t text_length, connection_parameters& parameters)
-{
- enum { part_name, part_prompt, part_list, part_value };
- const char* sp=output_text;
- const char* token=sp;
- connection_parameter parameter;
- int part_type=part_name;
- while(sp!=output_text+text_length)
- {
- switch(*sp)
- {
- case ';':
- parameters.emplace_back(parameter);
- parameter.reset();
- part_type=part_name;
- token=sp+1;
- break;
- case '=':
- if(part_type==part_prompt)
- parameter.m_prompt.assign(token, sp-token);
- part_type=part_value;
- token=sp+1;
- break;
- case ':':
- if(part_type==part_name)
- parameter.m_name.assign(token, sp-token);
- part_type=part_prompt;
- token=sp+1;
- break;
- case '{':
- part_type=part_list;
- parameter.m_value_list.clear();
- token=sp+1;
- break;;
- case '}':
- case ',':
- if(part_type==part_list)
- parameter.m_value_list.emplace_back(token, sp-token);
- token=sp+1;
- break;
- case '*':
- if(part_type==part_name && token==sp)
- {
- parameter.m_optinal=true;
- token=sp+1;
}
- break;
- case '?':
- token=sp+1;
- break;
+
+ template <typename EventLoop, typename Handler>
+ void async_wait_connect(SQLRETURN err, EventLoop &ev, Handler &&handler)
+ {
+ bind(ev);
+ m_BindFunc = [&ev](HANDLE hEvent)
+ {
+ return ev.add(hEvent);
+ };
+ if (is_still_executing(err))
+ {
+ async_wait(err, [this, handler](const error &e) mutable
+ {
+ if (!e) m_opened = true;
+ handler(e); });
+ }
+ else
+ {
+ handler(odbc::error(*this, err));
+ }
+ }
+
+ int connect_timeout() const
+ {
+ int timeout = 0;
+ verify_error(SQLGetConnectAttr(m_handle, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER)&timeout, 0, NULL));
+ return timeout;
+ }
+
+ private:
+ HANDLE m_hCompleteEvent;
+ std::function<qtl::event *(HANDLE)> m_BindFunc;
+ };
+
+ inline async_statement::async_statement(async_connection &db)
+ : base_statement(static_cast<base_database &>(db))
+ {
+ verify_error(SQLSetStmtAttr(m_handle, SQL_ATTR_ASYNC_ENABLE, (SQLPOINTER)SQL_ASYNC_ENABLE_ON, SQL_IS_INTEGER));
+ m_hCompleteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (m_hCompleteEvent == NULL)
+ {
+ throw std::system_error(std::error_code(GetLastError(), std::system_category()));
+ }
+ verify_error(SQLSetStmtAttr(m_handle, SQL_ATTR_ASYNC_STMT_EVENT, m_hCompleteEvent, SQL_IS_POINTER));
+ m_event = db.rebind(this->m_hCompleteEvent);
+ m_nQueryTimeout = query_timeout();
}
- ++sp;
- }
- if(!parameter.m_name.empty())
- parameters.emplace_back(parameter);
-}
-inline std::string base_database::create_connection_text(const connection_parameters& parameters)
-{
- std::ostringstream oss;
- for(auto& parameter : parameters)
- {
- if(parameter.m_assigned)
- oss<<parameter.m_name<<'='<<parameter.m_value<<';';
- }
- return oss.str();
-}
+#endif // ODBC 3.80
-inline base_statement::base_statement(base_database& db)
- : object(db.handle()), m_blob_buffer(NULL), m_binded_cols(false)
-{
-}
+ typedef qtl::transaction<database> transaction;
-} //odbc
+ template <typename Record>
+ using query_iterator = qtl::query_iterator<statement, Record>;
+
+ template <typename Record>
+ using query_result = qtl::query_result<statement, Record>;
+
+ template <typename Params>
+ inline statement &operator<<(statement &stmt, const Params ¶ms)
+ {
+ stmt.reset();
+ stmt.execute(params);
+ return stmt;
+ }
+
+ template <SQLSMALLINT Type>
+ inline error::error(const object<Type> &h, SQLINTEGER code)
+ {
+ m_errno = code;
+ if (code == SQL_ERROR || code == SQL_SUCCESS_WITH_INFO)
+ {
+ SQLSMALLINT i = 0;
+ SQLINTEGER err = SQL_SUCCESS;
+ SQLCHAR message[SQL_MAX_MESSAGE_LENGTH];
+ SQLCHAR state[SQL_SQLSTATE_SIZE + 1];
+ std::ostringstream oss;
+ SQLRETURN ret = SQLGetDiagRecA(object<Type>::handler_type, h.handle(), ++i, state, &err,
+ message, SQL_MAX_MESSAGE_LENGTH, NULL);
+ while (ret == SQL_SUCCESS)
+ {
+ oss << "[" << state << "] (" << err << ") " << message << std::endl;
+ ret = SQLGetDiagRecA(object<Type>::handler_type, h.handle(), ++i, state, &err,
+ message, SQL_MAX_MESSAGE_LENGTH, NULL);
+ }
+ m_errmsg = oss.str();
+ }
+ else if (code == SQL_INVALID_HANDLE)
+ {
+ m_errmsg = "Invalid handle.";
+ }
+ }
+
+ inline void base_database::parse_browse_string(const char *output_text, size_t text_length, connection_parameters ¶meters)
+ {
+ enum
+ {
+ part_name,
+ part_prompt,
+ part_list,
+ part_value
+ };
+ const char *sp = output_text;
+ const char *token = sp;
+ connection_parameter parameter;
+ int part_type = part_name;
+ while (sp != output_text + text_length)
+ {
+ switch (*sp)
+ {
+ case ';':
+ parameters.emplace_back(parameter);
+ parameter.reset();
+ part_type = part_name;
+ token = sp + 1;
+ break;
+ case '=':
+ if (part_type == part_prompt)
+ parameter.m_prompt.assign(token, sp - token);
+ part_type = part_value;
+ token = sp + 1;
+ break;
+ case ':':
+ if (part_type == part_name)
+ parameter.m_name.assign(token, sp - token);
+ part_type = part_prompt;
+ token = sp + 1;
+ break;
+ case '{':
+ part_type = part_list;
+ parameter.m_value_list.clear();
+ token = sp + 1;
+ break;
+ ;
+ case '}':
+ case ',':
+ if (part_type == part_list)
+ parameter.m_value_list.emplace_back(token, sp - token);
+ token = sp + 1;
+ break;
+ case '*':
+ if (part_type == part_name && token == sp)
+ {
+ parameter.m_optinal = true;
+ token = sp + 1;
+ }
+ break;
+ case '?':
+ token = sp + 1;
+ break;
+ }
+ ++sp;
+ }
+ if (!parameter.m_name.empty())
+ parameters.emplace_back(parameter);
+ }
+
+ inline std::string base_database::create_connection_text(const connection_parameters ¶meters)
+ {
+ std::ostringstream oss;
+ for (auto ¶meter : parameters)
+ {
+ if (parameter.m_assigned)
+ oss << parameter.m_name << '=' << parameter.m_value << ';';
+ }
+ return oss.str();
+ }
+
+ inline base_statement::base_statement(base_database &db)
+ : object(db.handle()), m_blob_buffer(NULL), m_binded_cols(false)
+ {
+ }
+
+ } // odbc
#ifdef _WIN32
-namespace mssql
-{
-
-class database : public odbc::database
-{
-public:
- explicit database(odbc::environment& env) : odbc::database(env) { }
- database(database&& src) : odbc::database(std::move(src)) { }
-
- void open(const char* server, const char* db=NULL, const char* user=NULL, const char* password=NULL)
+ namespace mssql
{
- std::ostringstream oss;
- oss<<"DRIVER={SQL Server};SERVER="<<server<<";";
- if(user==NULL)
- oss<<"UID=;PWD=;Trusted_Connection=yes;";
- else
+
+ class database : public odbc::database
{
- oss<<"UID="<<user<<";PWD=";
- if(password) oss<<password;
- oss<<";Trusted_Connection=no;";
- }
- oss<<"DATABASE="<<db;
- odbc::database::open(oss.str());
- }
-};
+ public:
+ explicit database(odbc::environment &env) : odbc::database(env) {}
+ database(database &&src) : odbc::database(std::move(src)) {}
+
+ void open(const char *server, const char *db = NULL, const char *user = NULL, const char *password = NULL)
+ {
+ std::ostringstream oss;
+ oss << "DRIVER={SQL Server};SERVER=" << server << ";";
+ if (user == NULL)
+ oss << "UID=;PWD=;Trusted_Connection=yes;";
+ else
+ {
+ oss << "UID=" << user << ";PWD=";
+ if (password)
+ oss << password;
+ oss << ";Trusted_Connection=no;";
+ }
+ oss << "DATABASE=" << db;
+ odbc::database::open(oss.str());
+ }
+ };
#ifdef QTL_ODBC_ENABLE_ASYNC_MODE
-class async_connection : public odbc::async_connection
-{
-public:
- explicit async_connection(odbc::environment& env) : odbc::async_connection(env) { }
- async_connection(async_connection&& src) : odbc::async_connection(std::move(src)) { }
-
- template<typename EventLoop, typename OpenHandler>
- void open(EventLoop& ev, const OpenHandler& handler, const char* server, const char* db = NULL, const char* user = NULL, const char* password = NULL)
- {
- std::ostringstream oss;
- oss << "DRIVER={ODBC Driver 11 for SQL Server};SERVER=" << server << ";";
- if (user == NULL)
- oss << "UID=;PWD=;Trusted_Connection=yes;";
- else
+ class async_connection : public odbc::async_connection
{
- oss << "UID=" << user << ";PWD=";
- if (password) oss << password;
- oss << ";Trusted_Connection=no;";
- }
- oss << "DATABASE=" << db;
- odbc::async_connection::open(ev, handler, oss.str());
- }
+ public:
+ explicit async_connection(odbc::environment &env) : odbc::async_connection(env) {}
+ async_connection(async_connection &&src) : odbc::async_connection(std::move(src)) {}
-};
+ template <typename EventLoop, typename OpenHandler>
+ void open(EventLoop &ev, const OpenHandler &handler, const char *server, const char *db = NULL, const char *user = NULL, const char *password = NULL)
+ {
+ std::ostringstream oss;
+ oss << "DRIVER={ODBC Driver 11 for SQL Server};SERVER=" << server << ";";
+ if (user == NULL)
+ oss << "UID=;PWD=;Trusted_Connection=yes;";
+ else
+ {
+ oss << "UID=" << user << ";PWD=";
+ if (password)
+ oss << password;
+ oss << ";Trusted_Connection=no;";
+ }
+ oss << "DATABASE=" << db;
+ odbc::async_connection::open(ev, handler, oss.str());
+ }
+ };
#endif
-} //mssql
+ } // mssql
-namespace msaccess
-{
-
-class database : public odbc::database
-{
-public:
- explicit database(odbc::environment& env) : odbc::database(env) { }
- database(database&& src) : odbc::database(std::forward<database>(src)) { }
-
- void open(const char* filename, const char* user=NULL, const char* password=NULL)
+ namespace msaccess
{
- std::ostringstream oss;
- oss<<"DRIVER={Microsoft Access Driver};DBQ="<<filename;
- if(user) oss<<";UID:"<<user;
- if(password) oss<<";PWD="<<password;
- odbc::database::open(oss.str());
- }
-};
-} //msaccess
+ class database : public odbc::database
+ {
+ public:
+ explicit database(odbc::environment &env) : odbc::database(env) {}
+ database(database &&src) : odbc::database(std::forward<database>(src)) {}
+
+ void open(const char *filename, const char *user = NULL, const char *password = NULL)
+ {
+ std::ostringstream oss;
+ oss << "DRIVER={Microsoft Access Driver};DBQ=" << filename;
+ if (user)
+ oss << ";UID:" << user;
+ if (password)
+ oss << ";PWD=" << password;
+ odbc::database::open(oss.str());
+ }
+ };
+
+ } // msaccess
#endif //_WIN32
diff --git a/include/qtl_odbc_pool.hpp b/include/qtl_odbc_pool.hpp
index eb5eb5e..dcfd82b 100644
--- a/include/qtl_odbc_pool.hpp
+++ b/include/qtl_odbc_pool.hpp
@@ -7,70 +7,71 @@
namespace qtl
{
-namespace odbc
-{
-
-class database_pool : public qtl::database_pool<database>
-{
-public:
- database_pool() { }
- virtual ~database_pool() { }
- virtual database* new_database() throw() override
+ namespace odbc
{
- database* db=NULL;
- try
- {
- db=new database(m_env);
- db->open(m_connection);
- }
- catch(error& e)
- {
- if(db)
- {
- delete db;
- db=NULL;
- }
- }
- return db;
- }
-protected:
- std::string m_connection;
- environment m_env;
-};
+ class database_pool : public qtl::database_pool<database>
+ {
+ public:
+ database_pool() {}
+ virtual ~database_pool() {}
+ virtual database *new_database() throw() override
+ {
+ database *db = NULL;
+ try
+ {
+ db = new database(m_env);
+ db->open(m_connection);
+ }
+ catch (error &e)
+ {
+ if (db)
+ {
+ delete db;
+ db = NULL;
+ }
+ }
+ return db;
+ }
+
+ protected:
+ std::string m_connection;
+ environment m_env;
+ };
#ifdef QTL_ODBC_ENABLE_ASYNC_MODE
-template<typename EventLoop>
-class async_pool : public qtl::async_pool<async_pool<EventLoop>, EventLoop, async_connection>
-{
- typedef qtl::async_pool<async_pool<EventLoop>, EventLoop, async_connection> base_class;
-public:
- async_pool(EventLoop& ev) : base_class(ev) { }
- virtual ~async_pool() { }
+ template <typename EventLoop>
+ class async_pool : public qtl::async_pool<async_pool<EventLoop>, EventLoop, async_connection>
+ {
+ typedef qtl::async_pool<async_pool<EventLoop>, EventLoop, async_connection> base_class;
- template<typename Handler>
- void new_connection(EventLoop& ev, Handler&& handler) throw()
- {
- async_connection* db = new async_connection(env);
- db->open(ev, [this, handler, db](const mysql::error& e) mutable {
+ public:
+ async_pool(EventLoop &ev) : base_class(ev) {}
+ virtual ~async_pool() {}
+
+ template <typename Handler>
+ void new_connection(EventLoop &ev, Handler &&handler) throw()
+ {
+ async_connection *db = new async_connection(env);
+ db->open(ev, [this, handler, db](const mysql::error &e) mutable
+ {
if (e)
{
delete db;
db = nullptr;
}
- handler(e, db);
- }, m_connection);
+ handler(e, db); }, m_connection);
+ }
+
+ protected:
+ std::string m_connection;
+ environment m_env;
+ };
+
+#endif // QTL_ODBC_ENABLE_ASYNC_MODE
+
}
-
-protected:
- std::string m_connection;
- environment m_env;
-};
-
-#endif //QTL_ODBC_ENABLE_ASYNC_MODE
-
-}
}
diff --git a/include/qtl_postgres.hpp b/include/qtl_postgres.hpp
index 5839a55..44687d7 100644
--- a/include/qtl_postgres.hpp
+++ b/include/qtl_postgres.hpp
@@ -31,10 +31,9 @@
#include <catalog/pg_type.h>
}
-
#ifdef open
#undef open
-#endif //open
+#endif // open
#ifdef vsnprintf
#undef vsnprintf
@@ -65,15 +64,15 @@
#ifdef _M_IX86
-#define _WS2_32_WINSOCK_SWAP_LONGLONG(l) \
- ( ( ((l) >> 56) & 0x00000000000000FFLL ) | \
- ( ((l) >> 40) & 0x000000000000FF00LL ) | \
- ( ((l) >> 24) & 0x0000000000FF0000LL ) | \
- ( ((l) >> 8) & 0x00000000FF000000LL ) | \
- ( ((l) << 8) & 0x000000FF00000000LL ) | \
- ( ((l) << 24) & 0x0000FF0000000000LL ) | \
- ( ((l) << 40) & 0x00FF000000000000LL ) | \
- ( ((l) << 56) & 0xFF00000000000000LL ) )
+#define _WS2_32_WINSOCK_SWAP_LONGLONG(l) \
+ ((((l) >> 56) & 0x00000000000000FFLL) | \
+ (((l) >> 40) & 0x000000000000FF00LL) | \
+ (((l) >> 24) & 0x0000000000FF0000LL) | \
+ (((l) >> 8) & 0x00000000FF000000LL) | \
+ (((l) << 8) & 0x000000FF00000000LL) | \
+ (((l) << 24) & 0x0000FF0000000000LL) | \
+ (((l) << 40) & 0x00FF000000000000LL) | \
+ (((l) << 56) & 0xFF00000000000000LL))
#ifndef htonll
__inline unsigned __int64 htonll(unsigned __int64 Value)
@@ -98,2243 +97,2306 @@
namespace qtl
{
-namespace postgres
-{
+ namespace postgres
+ {
-namespace detail
-{
+ namespace detail
+ {
- inline int16_t ntoh(int16_t v)
- {
- return static_cast<int16_t>(ntohs(v));
- }
- inline uint16_t ntoh(uint16_t v)
- {
- return ntohs(v);
- }
- inline int32_t ntoh(int32_t v)
- {
- return static_cast<int32_t>(ntohl(v));
- }
- inline uint32_t ntoh(uint32_t v)
- {
- return ntohl(v);
- }
- inline uint64_t ntoh(uint64_t v)
- {
+ inline int16_t ntoh(int16_t v)
+ {
+ return static_cast<int16_t>(ntohs(v));
+ }
+ inline uint16_t ntoh(uint16_t v)
+ {
+ return ntohs(v);
+ }
+ inline int32_t ntoh(int32_t v)
+ {
+ return static_cast<int32_t>(ntohl(v));
+ }
+ inline uint32_t ntoh(uint32_t v)
+ {
+ return ntohl(v);
+ }
+ inline uint64_t ntoh(uint64_t v)
+ {
#ifdef _WIN32
- return ntohll(v);
+ return ntohll(v);
#else
- return be64toh(v);
+ return be64toh(v);
#endif
- }
- inline int64_t ntoh(int64_t v)
- {
- return ntoh(static_cast<uint64_t>(v));
- }
+ }
+ inline int64_t ntoh(int64_t v)
+ {
+ return ntoh(static_cast<uint64_t>(v));
+ }
- template<typename T, typename = typename std::enable_if<std::is_integral<T>::value && !std::is_const<T>::value>::type>
- inline T& ntoh_inplace(T& v)
- {
- v = ntoh(v);
- return v;
- }
+ template <typename T, typename = typename std::enable_if<std::is_integral<T>::value && !std::is_const<T>::value>::type>
+ inline T &ntoh_inplace(T &v)
+ {
+ v = ntoh(v);
+ return v;
+ }
- inline int16_t hton(int16_t v)
- {
- return static_cast<int16_t>(htons(v));
- }
- inline uint16_t hton(uint16_t v)
- {
- return htons(v);
- }
- inline int32_t hton(int32_t v)
- {
- return static_cast<int32_t>(htonl(v));
- }
- inline uint32_t hton(uint32_t v)
- {
- return htonl(v);
- }
- inline uint64_t hton(uint64_t v)
- {
+ inline int16_t hton(int16_t v)
+ {
+ return static_cast<int16_t>(htons(v));
+ }
+ inline uint16_t hton(uint16_t v)
+ {
+ return htons(v);
+ }
+ inline int32_t hton(int32_t v)
+ {
+ return static_cast<int32_t>(htonl(v));
+ }
+ inline uint32_t hton(uint32_t v)
+ {
+ return htonl(v);
+ }
+ inline uint64_t hton(uint64_t v)
+ {
#ifdef _WIN32
- return htonll(v);
+ return htonll(v);
#else
- return htobe64(v);
+ return htobe64(v);
#endif
- }
- inline int64_t hton(int64_t v)
- {
- return hton(static_cast<uint64_t>(v));
- }
-
- template<typename T, typename = typename std::enable_if<std::is_integral<T>::value && !std::is_const<T>::value>::type>
- inline T& hton_inplace(T& v)
- {
- v = hton(v);
- return v;
- }
-
- template<typename T, typename = typename std::enable_if<std::is_integral<T>::value && !std::is_const<T>::value>::type>
- std::pair<std::vector<char>::iterator, size_t> push(std::vector<char>& buffer, T v)
- {
- v = hton_inplace(v);
- char* data = reinterpret_cast<char*>(&v);
- auto it = buffer.insert(buffer.end(), data, data + sizeof(T));
- return std::make_pair(it, sizeof(T));
- }
-
- template<typename T, typename = typename std::enable_if<std::is_integral<T>::value && !std::is_const<T>::value>::type>
- const char* pop(const char* data, T& v)
- {
- v = ntoh(*reinterpret_cast<const T*>(data));
- return data + sizeof(T);
- }
-}
-
-class base_database;
-class result;
-
-class error : public std::exception
-{
-public:
- error() : m_errmsg() { }
- explicit error(PGconn* conn, PGVerbosity verbosity = PQERRORS_DEFAULT, PGContextVisibility show_context = PQSHOW_CONTEXT_ERRORS)
- {
- //PQsetErrorVerbosity(conn, verbosity);
- //PQsetErrorContextVisibility(conn, show_context);
- const char* errmsg = PQerrorMessage(conn);
- if (errmsg) m_errmsg = errmsg;
- else m_errmsg.clear();
- }
-
- explicit error(PGresult* res)
- {
- const char* errmsg = PQresultErrorMessage(res);
- if (errmsg) m_errmsg = errmsg;
- else m_errmsg.clear();
- }
-
- explicit error(const char* errmsg) : m_errmsg(errmsg) { }
-
- virtual const char* what() const NOEXCEPT override { return m_errmsg.data(); }
- operator bool() const { return !m_errmsg.empty(); }
-
-protected:
- std::string m_errmsg;
-};
-
-class timeout : public error
-{
-public:
- timeout()
- {
- m_errmsg = "timeout";
- }
-};
-
-inline void verify_pgtypes_error(int ret)
-{
- if(ret && errno != 0)
- throw std::system_error(std::error_code(errno, std::generic_category()));
-}
-
-struct interval
-{
- ::interval* value;
-
- interval()
- {
- value = PGTYPESinterval_new();
- }
- explicit interval(char* str)
- {
- value = PGTYPESinterval_from_asc(str, nullptr);
- }
- interval(const interval& src) : interval()
- {
- verify_pgtypes_error(PGTYPESinterval_copy(src.value, value));
- }
- interval(interval&& src)
- {
- value = src.value;
- src.value = PGTYPESinterval_new();
- }
- ~interval()
- {
- PGTYPESinterval_free(value);
- }
-
- std::string to_string() const
- {
- return PGTYPESinterval_to_asc(value);
- }
-
- interval& operator=(const interval& src)
- {
- if(&src!=this)
- verify_pgtypes_error(PGTYPESinterval_copy(src.value, value));
- return *this;
- }
-};
-
-struct timestamp
-{
- ::timestamp value;
-
- timestamp() = default;
-
- static timestamp now()
- {
- timestamp result;
- PGTYPEStimestamp_current(&result.value);
- return result;
- }
- explicit timestamp(char* str)
- {
- value = PGTYPEStimestamp_from_asc(str, nullptr);
- verify_pgtypes_error(1);
- }
-
- int format(char* str, int n, const char* format) const
- {
- timestamp temp = *this;
- return PGTYPEStimestamp_fmt_asc(&temp.value, str, n, format);
- }
- static timestamp parse(char* str, const char* format)
- {
- timestamp result;
- verify_pgtypes_error(PGTYPEStimestamp_defmt_asc(str, format, &result.value));
- return result;
- }
-
- std::string to_string() const
- {
- char* str = PGTYPEStimestamp_to_asc(value);
- std::string result = str;
- PGTYPESchar_free(str);
- return result;
- }
-
- timestamp& operator += (const interval& span)
- {
- verify_pgtypes_error(PGTYPEStimestamp_add_interval(&value, span.value, &value));
- return *this;
- }
-
- timestamp& operator -= (const interval& span)
- {
- verify_pgtypes_error(PGTYPEStimestamp_sub_interval(&value, span.value, &value));
- return *this;
- }
-};
-
-inline timestamp operator+(const timestamp& a, const interval& b)
-{
- timestamp result=a;
- return result+=b;
-}
-
-inline timestamp operator-(const timestamp& a, const interval& b)
-{
- timestamp result=a;
- result -= b;
- return result;
-}
-
-
-struct timestamptz
-{
- ::TimestampTz value;
- /*
- timestamptz() = default;
- explicit timestamptz(pg_time_t v)
- {
- value = (TimestampTz)v -
- ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);
- value *= USECS_PER_SEC;
- }
-
- static timestamptz now()
- {
- timestamptz result;
- auto tp = std::chrono::system_clock::now();
- int sec = tp.time_since_epoch().count()*std::nano::num/std::nano::den;
- int usec = tp.time_since_epoch().count()*std::nano::num % std::nano::den;
-
- result.value = (TimestampTz)sec -
- ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);
- result.value = (result.value * USECS_PER_SEC) + usec;
-
- return result;
- }
- */
-};
-
-struct date
-{
- ::date value;
-
- date() = default;
- explicit date(timestamp dt)
- {
- value = PGTYPESdate_from_timestamp(dt.value);
- }
- explicit date(char* str)
- {
- value = PGTYPESdate_from_asc(str, nullptr);
- verify_pgtypes_error(1);
- }
- explicit date(int year, int month, int day)
- {
- int mdy[3] = { month, day, year };
- PGTYPESdate_mdyjul(mdy, &value);
- }
-
- std::string to_string() const
- {
- char* str = PGTYPESdate_to_asc(value);
- std::string result = str;
- PGTYPESchar_free(str);
- return str;
- }
-
- static date now()
- {
- date result;
- PGTYPESdate_today(&result.value);
- return result;
- }
-
- static date parse(char* str, const char* format)
- {
- date result;
- verify_pgtypes_error(PGTYPESdate_defmt_asc(&result.value, format, str));
- return result;
- }
-
- std::string format(const char* format)
- {
- std::string result;
- result.resize(128);
- verify_pgtypes_error(PGTYPESdate_fmt_asc(value, format, const_cast<char*>(result.data())));
- result.resize(strlen(result.data()));
- return result;
- }
-
- std::tuple<int, int, int> get_date()
- {
- int mdy[3];
- PGTYPESdate_julmdy(value, mdy);
- return std::make_tuple(mdy[2], mdy[0], mdy[1]);
- }
-
- int dayofweek()
- {
- return PGTYPESdate_dayofweek(value);
- }
-};
-
-struct decimal
-{
- ::decimal value;
-};
-
-struct numeric
-{
- ::numeric* value;
-
- numeric()
- {
- value = PGTYPESnumeric_new();
- }
- numeric(int v) : numeric()
- {
- verify_pgtypes_error(PGTYPESnumeric_from_int(v, value));
- }
- numeric(long v) : numeric()
- {
- verify_pgtypes_error(PGTYPESnumeric_from_long(v, value));
- }
- numeric(double v) : numeric()
- {
- verify_pgtypes_error(PGTYPESnumeric_from_double(v, value));
- }
- numeric(const decimal& v) : numeric()
- {
- verify_pgtypes_error(PGTYPESnumeric_from_decimal(const_cast<::decimal*>(&v.value), value));
- }
- numeric(const numeric& src) : numeric()
- {
- verify_pgtypes_error(PGTYPESnumeric_copy(src.value, value));
- }
- explicit numeric(const char* str)
- {
- value = PGTYPESnumeric_from_asc(const_cast<char*>(str), nullptr);
- }
- ~numeric()
- {
- PGTYPESnumeric_free(value);
- }
-
- operator double() const
- {
- double result;
- verify_pgtypes_error(PGTYPESnumeric_to_double(value, &result));
- return result;
- }
-
- operator int() const
- {
- int result;
- verify_pgtypes_error(PGTYPESnumeric_to_int(value, &result));
- return result;
- }
-
- operator long() const
- {
- long result;
- verify_pgtypes_error(PGTYPESnumeric_to_long(value, &result));
- return result;
- }
-
- operator decimal() const
- {
- decimal result;
- verify_pgtypes_error(PGTYPESnumeric_to_decimal(value, &result.value));
- return result;
- }
-
- int compare(const numeric& other) const
- {
- return PGTYPESnumeric_cmp(value, other.value);
- }
-
- inline numeric& operator+=(const numeric& b)
- {
- verify_pgtypes_error(PGTYPESnumeric_add(value, b.value, value));
- return *this;
- }
-
- inline numeric& operator-=(const numeric& b)
- {
- verify_pgtypes_error(PGTYPESnumeric_sub(value, b.value, value));
- return *this;
- }
-
- inline numeric& operator*=(const numeric& b)
- {
- verify_pgtypes_error(PGTYPESnumeric_mul(value, b.value, value));
- return *this;
- }
-
- inline numeric& operator/=(const numeric& b)
- {
- verify_pgtypes_error(PGTYPESnumeric_div(value, b.value, value));
- return *this;
- }
-
- std::string to_string(int dscale=-1) const
- {
- char* str = PGTYPESnumeric_to_asc(value, dscale);
- std::string result = str;
- PGTYPESchar_free(str);
- return result;
- }
-};
-
-inline numeric operator+(const numeric& a, const numeric& b)
-{
- numeric result;
- verify_pgtypes_error(PGTYPESnumeric_add(a.value, b.value, result.value));
- return result;
-}
-
-inline numeric operator-(const numeric& a, const numeric& b)
-{
- numeric result;
- verify_pgtypes_error(PGTYPESnumeric_sub(a.value, b.value, result.value));
- return result;
-}
-
-inline numeric operator*(const numeric& a, const numeric& b)
-{
- numeric result;
- verify_pgtypes_error(PGTYPESnumeric_mul(a.value, b.value, result.value));
- return result;
-}
-
-inline numeric operator/(const numeric& a, const numeric& b)
-{
- numeric result;
- verify_pgtypes_error(PGTYPESnumeric_div(a.value, b.value, result.value));
- return result;
-}
-
-inline bool operator==(const numeric& a, const numeric& b)
-{
- return a.compare(b) == 0;
-}
-
-inline bool operator<(const numeric& a, const numeric& b)
-{
- return a.compare(b) < 0;
-}
-
-inline bool operator>(const numeric& a, const numeric& b)
-{
- return a.compare(b) > 0;
-}
-
-inline bool operator<=(const numeric& a, const numeric& b)
-{
- return a.compare(b) <= 0;
-}
-
-inline bool operator>=(const numeric& a, const numeric& b)
-{
- return a.compare(b) >= 0;
-}
-
-inline bool operator!=(const numeric& a, const numeric& b)
-{
- return a.compare(b) != 0;
-}
-
-class large_object : public qtl::blobbuf
-{
-public:
- large_object() : m_conn(nullptr), m_id(InvalidOid), m_fd(-1) { }
- large_object(PGconn* conn, Oid loid, std::ios_base::openmode mode)
- {
- open(conn, loid, mode);
- }
- large_object(const large_object&) = delete;
- large_object(large_object&& src)
- {
- swap(src);
- src.m_conn = nullptr;
- src.m_fd = -1;
- }
- ~large_object()
- {
- close();
- }
-
- static large_object create(PGconn* conn, Oid loid = InvalidOid)
- {
- Oid oid = lo_create(conn, loid);
- if (oid == InvalidOid)
- throw error(conn);
- return large_object(conn, oid, std::ios::in|std::ios::out|std::ios::binary);
- }
- static large_object load(PGconn* conn, const char* filename, Oid loid = InvalidOid)
- {
- Oid oid = lo_import_with_oid(conn, filename, loid);
- if (oid == InvalidOid)
- throw error(conn);
- return large_object(conn, oid, std::ios::in | std::ios::out | std::ios::binary);
- }
- void save(const char* filename) const
- {
- if (lo_export(m_conn, m_id, filename) < 0)
- throw error(m_conn);
- }
-
- void unlink()
- {
- close();
- if (lo_unlink(m_conn, m_id) < 0)
- throw error(m_conn);
- }
-
- large_object& operator=(const large_object&) = delete;
- large_object& operator=(large_object&& src)
- {
- if (this != &src)
- {
- swap(src);
- src.close();
- }
- return *this;
- }
- bool is_open() const { return m_fd >= 0; }
- Oid oid() const { return m_id; }
-
- void open(PGconn* conn, Oid loid, std::ios_base::openmode mode)
- {
- int lomode = 0;
- if (mode&std::ios_base::in)
- lomode |= INV_READ;
- if (mode&std::ios_base::out)
- lomode |= INV_WRITE;
- m_conn = conn;
- m_id = loid;
- m_fd = lo_open(m_conn, loid, lomode);
- if (m_fd < 0)
- throw error(m_conn);
-
- m_size = size();
- init_buffer(mode);
- if (mode&std::ios_base::trunc)
- {
- if (lo_truncate(m_conn, m_fd, 0) < 0)
- throw error(m_conn);
- }
- }
-
- void close()
- {
- if (m_fd >= 0)
- {
- overflow();
- if (lo_close(m_conn, m_fd) < 0)
- throw error(m_conn);
- m_fd = -1;
- }
- }
-
- void flush()
- {
- if (m_fd >= 0)
- overflow();
- }
-
- size_t size() const
- {
- pg_int64 size = 0;
- if (m_fd >= 0)
- {
- pg_int64 org = lo_tell64(m_conn, m_fd);
- size = lo_lseek64(m_conn, m_fd, 0, SEEK_END);
- lo_lseek64(m_conn, m_fd, org, SEEK_SET);
- }
- return size;
- }
-
- void resize(size_t n)
- {
- if (m_fd >= 0 && lo_truncate64(m_conn, m_fd, n) < 0)
- throw error(m_conn);
- }
-
- void swap(large_object& other)
- {
- std::swap(m_conn, other.m_conn);
- std::swap(m_id, other.m_id);
- std::swap(m_fd, other.m_fd);
- qtl::blobbuf::swap(other);
- }
-
-protected:
- enum { default_buffer_size = 4096 };
-
- virtual bool read_blob(char* buffer, off_type& count, pos_type position) override
- {
- return lo_lseek64(m_conn, m_fd, position, SEEK_SET) >= 0 && lo_read(m_conn, m_fd, buffer, count) > 0;
- }
- virtual void write_blob(const char* buffer, size_t count) override
- {
- if (lo_write(m_conn, m_fd, buffer, count) < 0)
- throw error(m_conn);
- }
-
-private:
- PGconn* m_conn;
- Oid m_id;
- int m_fd;
-};
-
-struct array_header
-{
- int32_t ndim;
- int32_t flags;
- int32_t elemtype;
- struct dimension {
- int32_t length;
- int32_t lower_bound;
- } dims[1];
-};
-
-/*
- template<typename T>
- struct oid_traits
- {
- typedef T value_type;
- static Oid type_id;
- static Oid array_type_id; //optional
- static const char* get(value_type& result, const char* begin, const char* end);
- static std::pair<const char*, size_t> data(const T& v, std::vector<char*>& buffer);
- };
-*/
-
-template<typename T, Oid id>
-struct base_object_traits
-{
- typedef T value_type;
- enum { type_id = id };
- static bool is_match(Oid v)
- {
- return v == type_id;
- }
-};
-
-template<typename T>
-struct object_traits;
-
-#define QTL_POSTGRES_SIMPLE_TRAITS(T, oid, array_oid) \
-template<> struct object_traits<T> : public base_object_traits<T, oid> { \
- enum { array_type_id = array_oid }; \
- static const char* get(value_type& result, const char* data, const char* end) \
- { \
- result = *reinterpret_cast<const value_type*>(data); \
- return data+sizeof(value_type); \
- } \
- static std::pair<const char*, size_t> data(const T& v, std::vector<char>& /*data*/) { \
- return std::make_pair(reinterpret_cast<const char*>(&v), sizeof(T)); \
- } \
-};
-
-QTL_POSTGRES_SIMPLE_TRAITS(bool, BOOLOID, 1000)
-QTL_POSTGRES_SIMPLE_TRAITS(char, CHAROID, 1002)
-QTL_POSTGRES_SIMPLE_TRAITS(float, FLOAT4OID, FLOAT4ARRAYOID)
-QTL_POSTGRES_SIMPLE_TRAITS(double, FLOAT8OID, 1022)
-
-template<typename T, Oid id, Oid array_id>
-struct integral_traits : public base_object_traits<T, id>
-{
- enum { array_type_id = array_id };
- typedef typename base_object_traits<T, id>::value_type value_type;
- static const char* get(value_type& v, const char* data, const char* end)
- {
- return detail::pop(data, v);
- }
- static std::pair<const char*, size_t> data(value_type v, std::vector<char>& buffer)
- {
- size_t n = buffer.size();
- detail::push(buffer, v);
- return std::make_pair(buffer.data()+n, buffer.size()-n);
- }
-};
-
-template<> struct object_traits<int16_t> : public integral_traits<int16_t, INT2OID, INT2ARRAYOID>
-{
-};
-
-template<> struct object_traits<int32_t> : public integral_traits<int32_t, INT4OID, INT4ARRAYOID>
-{
-};
-
-template<> struct object_traits<int64_t> : public integral_traits<int64_t, INT8OID, 1016>
-{
-};
-
-template<> struct object_traits<Oid> : public integral_traits<Oid, OIDOID, OIDARRAYOID>
-{
-};
-
-template<typename T>
-struct text_traits : public base_object_traits<T, TEXTOID>
-{
- enum { array_type_id = TEXTARRAYOID };
-};
-
-template<> struct object_traits<const char*> : public text_traits<const char*>
-{
- static bool is_match(Oid v)
- {
- return v == TEXTOID || v == VARCHAROID || v == BPCHAROID;
- }
- static const char* get(const char*& result, const char* data, const char* end)
- {
- result = data;
- return end;
- }
- static std::pair<const char*, size_t> data(const char* v, std::vector<char>& /*buffer*/)
- {
- return std::make_pair(v, strlen(v));
- }
-};
-
-template<> struct object_traits<char*> : public object_traits<const char*>
-{
-};
-
-template<> struct object_traits<std::string> : public text_traits<std::string>
-{
- static bool is_match(Oid v)
- {
- return v == TEXTOID || v == VARCHAROID || v == BPCHAROID;
- }
- static const char* get(value_type& result, const char* data, const char* end)
- {
- result.assign(data, end);
- return end;
- }
- static std::pair<const char*, size_t> data(const std::string& v, std::vector<char>& /*buffer*/)
- {
- return std::make_pair(v.data(), v.size());
- }
-};
-
-template<> struct object_traits<timestamp> : public base_object_traits<timestamp, TIMESTAMPOID>
-{
- enum { array_type_id = TIMESTAMPOID+1 };
- static const char* get(value_type& result, const char* data, const char* end)
- {
- result = *reinterpret_cast<const timestamp*>(data);
- result.value = detail::ntoh(result.value);
- return data+sizeof(timestamp);
- }
- static std::pair<const char*, size_t> data(const timestamp& v, std::vector<char>& buffer)
- {
- size_t n = buffer.size();
- detail::push(buffer, v.value);
- return std::make_pair(buffer.data()+n, buffer.size()-n);
- }
-};
-
-template<> struct object_traits<timestamptz> : public base_object_traits<timestamptz, TIMESTAMPTZOID>
-{
- enum { array_type_id = TIMESTAMPTZOID+1 };
- static const char* get(value_type& result, const char* data, const char* end)
- {
- result = *reinterpret_cast<const timestamptz*>(data);
- result.value = detail::ntoh(result.value);
- return data+sizeof(timestamptz);
- }
- static std::pair<const char*, size_t> data(const timestamptz& v, std::vector<char>& buffer)
- {
- size_t n = buffer.size();
- detail::push(buffer, v.value);
- return std::make_pair(buffer.data() + n, buffer.size() - n);
- }
-};
-
-template<> struct object_traits<interval> : public base_object_traits<interval, INTERVALOID>
-{
- enum { array_type_id = INTERVALOID+1 };
- static const char* get(value_type& result, const char* data, const char* end)
- {
- const ::interval* value = reinterpret_cast<const ::interval*>(data);
- result.value->time = detail::ntoh(value->time);
- result.value->month = detail::ntoh(value->month);
- return data+sizeof(interval);
- }
- static std::pair<const char*, size_t> data(const interval& v, std::vector<char>& buffer)
- {
- size_t n = buffer.size();
- detail::push(buffer, v.value->time);
- detail::push(buffer, v.value->month);
- return std::make_pair(buffer.data()+n, buffer.size()-n);
- }
-};
-
-template<> struct object_traits<date> : public base_object_traits<date, DATEOID>
-{
- enum { array_type_id = 1182 };
- static const char* get(value_type& result, const char* data, const char* end)
- {
- result = *reinterpret_cast<const date*>(data);
- result.value = detail::ntoh(result.value);
- return data+sizeof(date);
- }
- static std::pair<const char*, size_t> data(const date& v, std::vector<char>& buffer)
- {
- size_t n=buffer.size();
- detail::push(buffer, v.value);
- return std::make_pair(buffer.data()+n, buffer.size()-n);
- }
-};
-
-template<typename T>
-struct bytea_traits : public base_object_traits<T, BYTEAOID>
-{
- enum { array_type_id = 1001 };
-};
-
-template<> struct object_traits<qtl::const_blob_data> : public bytea_traits<qtl::const_blob_data>
-{
- static const char* get(value_type& result, const char* data, const char* end)
- {
- result.data = data;
- result.size = end-data;
- return end;
- }
- static std::pair<const char*, size_t> data(const qtl::const_blob_data& v, std::vector<char>& /*buffer*/)
- {
- assert(v.size <= UINT32_MAX);
- return std::make_pair(static_cast<const char*>(v.data), v.size);
- }
-};
-
-template<> struct object_traits<qtl::blob_data> : public bytea_traits<qtl::blob_data>
-{
- static const char* get(qtl::blob_data& value, const char* data, const char* end)
- {
- if (value.size < end-data)
- throw std::out_of_range("no enough buffer to receive blob data.");
- memcpy(value.data, data, end-data);
- return end;
- }
- static std::pair<const char*, size_t> data(const qtl::blob_data& v, std::vector<char>& /*buffer*/)
- {
- assert(v.size <= UINT32_MAX);
- return std::make_pair(static_cast<char*>(v.data), v.size);
- }
-};
-
-template<> struct object_traits<std::vector<uint8_t>> : public bytea_traits<std::vector<uint8_t>>
-{
- static const char* get(value_type& result, const char* data, const char* end)
- {
- result.assign(data, end);
- return end;
- }
- static std::pair<const char*, size_t> data(const std::vector<uint8_t>& v, std::vector<char>& /*buffer*/)
- {
- assert(v.size() <= UINT32_MAX);
- return std::make_pair(reinterpret_cast<const char*>(v.data()), v.size());
- }
-};
-
-template<> struct object_traits<large_object> : public base_object_traits<large_object, OIDOID>
-{
- enum { array_type_id = OIDARRAYOID };
- static value_type get(PGconn* conn, const char* data, const char* end)
- {
- int32_t oid;
- object_traits<int32_t>::get(oid, data, end);
- return large_object(conn, oid, std::ios::in | std::ios::out | std::ios::binary);
- }
- static std::pair<const char*, size_t> data(const large_object& v, std::vector<char>& buffer)
- {
- return object_traits<int32_t>::data(v.oid(), buffer);
- }
-};
-
-template<typename T, Oid id>
-struct vector_traits : public base_object_traits<std::vector<T>, id>
-{
- typedef typename base_object_traits<std::vector<T>, id>::value_type value_type;
- static const char* get(value_type& result, const char* data, const char* end)
- {
- if (end - data < sizeof(array_header))
- throw std::overflow_error("insufficient data left in message");
-
- array_header header = *reinterpret_cast<const array_header*>(data);
- detail::ntoh_inplace(header.ndim);
- detail::ntoh_inplace(header.flags);
- detail::ntoh_inplace(header.elemtype);
- detail::ntoh_inplace(header.dims[0].length);
- detail::ntoh_inplace(header.dims[0].lower_bound);
- if (header.ndim != 1 || !object_traits<T>::is_match(header.elemtype))
- throw std::bad_cast();
-
- data += sizeof(array_header);
- result.reserve(header.dims[0].length);
-
- for (int32_t i = 0; i != header.dims[0].length; i++)
- {
- int32_t size;
- T value;
- data = detail::pop(data, size);
- if (end - data < size)
- throw std::overflow_error("insufficient data left in message");
- data = object_traits<T>::get(value, data, data + size);
- if (data > end)
- throw std::overflow_error("insufficient data left in message");
- result.push_back(value);
- }
- return data;
- }
- static std::pair<const char*, size_t> data(const std::vector<T>& v, std::vector<char>& buffer)
- {
- assert(v.size() <= INT32_MAX);
- size_t n = buffer.size();
- buffer.resize(n+sizeof(array_header));
- array_header* header = reinterpret_cast<array_header*>(buffer.data()+n);
- header->ndim = detail::hton(1);
- header->flags = detail::hton(0);
- header->elemtype = detail::hton(static_cast<int32_t>(object_traits<T>::type_id));
- header->dims[0].length = detail::hton(static_cast<int32_t>(v.size()));
- header->dims[0].lower_bound = detail::hton(1);
-
- std::vector<char> temp;
- for (const T& e : v)
- {
- std::pair<const char*, size_t> blob = object_traits<T>::data(e, temp);
- detail::push(buffer, static_cast<int32_t>(blob.second));
- buffer.insert(buffer.end(), blob.first, blob.first + blob.second);
- }
- return std::make_pair(buffer.data()+n, buffer.size()-n);
- }
-};
-
-template<typename Iterator, Oid id>
-struct iterator_traits : public base_object_traits<Iterator, id>
-{
- static const char* get(Iterator first, Iterator last, const char* data, const char* end)
- {
- if (end - data < sizeof(array_header))
- throw std::overflow_error("insufficient data left in message");
-
- array_header header = *reinterpret_cast<const array_header*>(data);
- detail::ntoh_inplace(header.ndim);
- detail::ntoh_inplace(header.flags);
- detail::ntoh_inplace(header.elemtype);
- detail::ntoh_inplace(header.dims[0].length);
- detail::ntoh_inplace(header.dims[0].lower_bound);
- if (header.ndim != 1 || !object_traits<typename std::iterator_traits<Iterator>::value_type>::is_match(header.elemtype))
- throw std::bad_cast();
-
- data += sizeof(array_header);
- if (std::distance(first, last) < header.dims[0].length)
- throw std::out_of_range("length of array out of range");
-
- Iterator it = first;
- for (int32_t i = 0; i != header.dims[0].length; i++, it++)
- {
- int32_t size;
- data = detail::pop(data, size);
- if (end - data < size)
- throw std::overflow_error("insufficient data left in message");
- data = object_traits<typename std::iterator_traits<Iterator>::value_type>::get(*it, data, data + size);
- if (data >= end)
- throw std::overflow_error("insufficient data left in message");
- }
- return data;
- }
- static std::pair<const char*, size_t> data(Iterator first, Iterator last, std::vector<char>& buffer)
- {
- assert(std::distance(first, last) <= INT32_MAX);
- size_t n = buffer.size();
- buffer.resize(n + sizeof(array_header));
- array_header* header = reinterpret_cast<array_header*>(buffer.data() + n);
- header->ndim = detail::hton(1);
- header->flags = detail::hton(0);
- header->elemtype = detail::hton(static_cast<int32_t>(object_traits<typename std::iterator_traits<Iterator>::value_type>::type_id));
- header->dims[0].length = detail::hton(static_cast<int32_t>(std::distance(first, last)));
- header->dims[0].lower_bound = detail::hton(1);
-
- std::vector<char> temp;
- for (Iterator it=first; it!=last; it++)
- {
- std::pair<const char*, size_t> blob = object_traits<typename std::iterator_traits<Iterator>::value_type>::data(*it, temp);
- detail::push(buffer, static_cast<int32_t>(blob.second));
- buffer.insert(buffer.end(), blob.first, blob.first + blob.second);
- }
- return std::make_pair(buffer.data() + n, buffer.size() - n);
- }
-};
-
-template<typename Iterator, Oid id>
-struct range_traits : public base_object_traits<std::pair<Iterator, Iterator>, id>
-{
- static const char* get(std::pair<Iterator, Iterator>& result, const char* data, const char* end)
- {
- return iterator_traits<Iterator, id>::get(result.first, result.second, data, end);
- }
- static std::pair<const char*, size_t> data(const std::pair<Iterator, Iterator>& v, std::vector<char>& buffer)
- {
- return iterator_traits<Iterator, id>::data(v.first, v.second, buffer);
- }
-};
-
-template<typename T>
-struct object_traits<std::vector<T>> : public vector_traits<T, object_traits<T>::array_type_id>
-{
-};
-
-template<typename Iterator>
-struct object_traits<std::pair<typename std::enable_if<std::is_object<typename std::iterator_traits<Iterator>::value_type>::value, Iterator>::type, Iterator>> :
- public range_traits<Iterator, object_traits<typename std::iterator_traits<Iterator>::value_type>::array_type_id>
-{
-};
-
-template<typename T, size_t N, Oid id>
-struct carray_traits : public base_object_traits<T(&)[N], id>
-{
- static const char* get(T (&result)[N], const char* data, const char* end)
- {
- return iterator_traits<T*, id>::get(std::begin(result), std::end(result), data, end);
- }
- static std::pair<const char*, size_t> data(const T (&v)[N], std::vector<char>& buffer)
- {
- return iterator_traits<const T*, id>::data(std::begin(v), std::end(v), buffer);
- }
-};
-
-template<typename T, size_t N, Oid id>
-struct array_traits : public base_object_traits<std::array<T, N>, id>
-{
- static const char* get(std::array<T, N>& result, const char* data, const char* end)
- {
- return iterator_traits<T*, id>::get(std::begin(result), std::end(result), data, end);
- }
- static std::pair<const char*, size_t> data(const std::array<T, N>& v, std::vector<char>& buffer)
- {
- return iterator_traits<T*, id>::data(std::begin(v), std::end(v), buffer);
- }
-};
-
-template<typename T, size_t N> struct object_traits<T (&)[N]> : public carray_traits<T, N, object_traits<T>::array_type_id>
-{
-};
-
-template<typename T, size_t N> struct object_traits<std::array<T, N>> : public array_traits<T, N, object_traits<T>::array_type_id>
-{
-};
-
-namespace detail
-{
-
- struct field_header
- {
- Oid type;
- int32_t length;
- };
-
- template<typename Type>
- static const char* get_field(Type& field, const char* data, const char* end)
- {
- field_header header = *reinterpret_cast<const field_header*>(data);
- detail::ntoh_inplace(header.type);
- detail::ntoh_inplace(header.length);
- data += sizeof(field_header);
- if (end - data < header.length)
- throw std::overflow_error("insufficient data left in message");
-
- return object_traits<Type>::get(field, data, data + header.length);
- }
-
- template<typename Tuple, size_t N>
- struct get_field_helper
- {
- const char* operator()(Tuple& result, const char* data, const char* end)
- {
- if (end - data < sizeof(field_header))
- throw std::overflow_error("insufficient data left in message");
-
- auto& field = std::get<std::tuple_size<Tuple>::value - N>(result);
- data = get_field(field, data, end);
- get_field_helper<Tuple, N - 1>()(result, data, end);
- return data;
- }
- };
- template<typename Tuple>
- struct get_field_helper<Tuple, 1>
- {
- const char* operator()(Tuple& result, const char* data, const char* end)
- {
- if (end - data < sizeof(field_header))
- throw std::overflow_error("insufficient data left in message");
-
- auto& field = std::get<std::tuple_size<Tuple>::value - 1>(result);
- return get_field(field, data, end);
- }
- };
-
- template<typename Type>
- static void push_field(const Type& field, std::vector<char>& buffer)
- {
- std::vector<char> temp;
- detail::push(buffer, static_cast<int32_t>(object_traits<Type>::type_id));
- auto result = object_traits<Type>::data(field, temp);
- detail::push(buffer, static_cast<int32_t>(result.second));
- buffer.insert(buffer.end(), result.first, result.first + result.second);
- }
-
- template<typename Tuple, size_t N>
- struct push_field_helper
- {
- void operator()(const Tuple& data, std::vector<char>& buffer)
- {
- const auto& field = std::get<std::tuple_size<Tuple>::value - N>(data);
- push_field(field, buffer);
- push_field_helper<Tuple, N - 1>()(data, buffer);
- }
- };
- template<typename Tuple>
- struct push_field_helper<Tuple, 1>
- {
- void operator()(const Tuple& data, std::vector<char>& buffer)
- {
- const auto& field = std::get<std::tuple_size<Tuple>::value - 1>(data);
- push_field(field, buffer);
- }
- };
-
- template<typename Tuple>
- static const char* get_fields(Tuple& result, const char* data, const char* end)
- {
- return get_field_helper<Tuple, std::tuple_size<Tuple>::value>()(result, data, end);
- }
-
- template<typename Tuple>
- static void push_fields(const Tuple& data, std::vector<char>& buffer)
- {
- push_field_helper<Tuple, std::tuple_size<Tuple>::value>()(data, buffer);
- }
-
-}
-
-template<typename Tuple, Oid id>
-struct tuple_traits : public base_object_traits<Tuple, id>
-{
- typedef typename base_object_traits<Tuple, id>::value_type value_type;
- static const char* get(value_type& result, const char* data, const char* end)
- {
- int32_t count;
- data = detail::pop(data, count);
- if (data >= end)
- throw std::overflow_error("insufficient data left in message");
- if (std::tuple_size<Tuple>::value != count)
- throw std::bad_cast();
- return detail::get_fields(result, data, end);
- }
- static std::pair<const char*, size_t> data(const value_type& v, std::vector<char>& buffer)
- {
- size_t n = buffer.size();
- detail::push(buffer, static_cast<int32_t>(std::tuple_size<value_type>::value));
- detail::push_fields(v, buffer);
- return std::make_pair(buffer.data()+n, buffer.size()-n);
- }
-};
-
-template<typename... Types>
-struct object_traits<std::tuple<Types...>> : public tuple_traits<std::tuple<Types...>, InvalidOid>
-{
-};
-
-template<typename T1, typename T2>
-struct object_traits<std::pair<T1, T2>> : public tuple_traits<std::pair<T1, T2>, InvalidOid>
-{
-};
-
-struct binder
-{
- binder() = default;
- template<typename T>
- explicit binder(const T& v)
- {
- m_type = object_traits<T>::value();
- auto pair = object_traits<T>::data(v);
- m_value = pair.first;
- m_length = pair.second;
- }
- binder(const char* data, size_t n, Oid oid)
- {
- m_type = oid;
- m_value = data;
- m_length = n;
- }
-
- Oid constexpr type() const { return m_type; }
- size_t length() const { return m_length; }
- const char* value() const { return m_value; }
-
- template<typename T>
- T get()
- {
- if (!object_traits<T>::is_match(m_type))
- throw std::bad_cast();
-
- T v;
- object_traits<T>::get(v, m_value, m_value + m_length);
- return v;
- }
- template<typename T>
- T get(PGconn* conn)
- {
- if (!object_traits<T>::is_match(m_type))
- throw std::bad_cast();
-
- return object_traits<T>::get(conn, m_value, m_value + m_length);
- }
- template<typename T>
- void get(T& v)
- {
- if (object_traits<T>::type_id!= InvalidOid && !object_traits<T>::is_match(m_type))
- throw std::bad_cast();
-
- object_traits<T>::get(v, m_value, m_value + m_length);
- }
-
- void bind(std::nullptr_t)
- {
- m_value = nullptr;
- m_length = 0;
- }
- void bind(qtl::null)
- {
- bind(nullptr);
- }
-
- template<typename T, typename = typename std::enable_if<!std::is_array<T>::value>::type>
- void bind(const T& v)
- {
- typedef typename std::decay<T>::type param_type;
- if (m_type!=0 && !object_traits<param_type>::is_match(m_type))
- throw std::bad_cast();
-
- auto pair = object_traits<param_type>::data(v, m_data);
- m_value = pair.first;
- m_length = pair.second;
- }
- void bind(const char* data, size_t length=0)
- {
- m_value = data;
- if(length>0) m_length = length;
- else m_length = strlen(data);
- }
- template<typename T, size_t N>
- void bind(const T(&v)[N])
- {
- if (m_type != 0 && !object_traits<T(&)[N]>::is_match(m_type))
- throw std::bad_cast();
-
- auto pair = object_traits<T(&)[N]>::data(v, m_data);
- m_value = pair.first;
- m_length = pair.second;
- }
-
-private:
- Oid m_type;
- const char* m_value;
- size_t m_length;
- std::vector<char> m_data;
-};
-
-template<size_t N, size_t I, typename Arg, typename... Other>
-inline void make_binder_list_helper(std::array<binder, N>& binders, Arg&& arg, Other&&... other)
-{
- binders[I]=binder(arg);
- make_binder_list_helper<N, I+1>(binders, std::forward<Other>(other)...);
-}
-
-template<typename... Args>
-inline std::array<binder, sizeof...(Args)> make_binder_list(Args&&... args)
-{
- std::array<binder, sizeof...(Args)> binders;
- binders.reserve(sizeof...(Args));
- make_binder_list_helper<sizeof...(Args), 0>(binders, std::forward<Args>(args)...);
- return binders;
-}
-
-template<typename T>
-inline bool in_impl(const T& from, const T& to)
-{
- return std::equal_to<T>()(from, to);
-}
-
-template<typename T, typename... Ts >
-inline bool in_impl(const T& from, const T& to, const Ts&... other)
-{
- return std::equal_to<T>()(from, to) || in_impl(from, other...);
-}
-
-template<typename T, T... values>
-inline bool in(const T& v)
-{
- return in_impl(v, values...);
-}
-
-class result
-{
-public:
- result(PGresult* res) : m_res(res) { }
- result(const result&) = delete;
- result(result&& src)
- {
- m_res = src.m_res;
- src.m_res = nullptr;
- }
-
- result& operator=(const result&) = delete;
- result& operator=(result&& src)
- {
- if (this != &src)
- {
- clear();
- m_res = src.m_res;
- src.m_res = nullptr;
- }
- return *this;
- }
- ~result()
- {
- clear();
- }
-
- PGresult* handle() const { return m_res; }
- operator bool() const { return m_res != nullptr; }
-
- ExecStatusType status() const
- {
- return PQresultStatus(m_res);
- }
-
- long long affected_rows() const
- {
- char* result = PQcmdTuples(m_res);
- if (result)
- return strtoll(result, nullptr, 10);
- else
- return 0LL;
- }
-
- unsigned int get_column_count() const { return PQnfields(m_res); }
-
- int get_param_count() const
- {
- return PQnparams(m_res);
- }
-
- Oid get_param_type(int col) const
- {
- return PQparamtype(m_res, col);
- }
-
- const char* get_column_name(int col) const
- {
- return PQfname(m_res, col);
- }
- int get_column_index(const char* name) const
- {
- return PQfnumber(m_res, name);
- }
- int get_column_length(int col) const
- {
- return PQfsize(m_res, col);
- }
- Oid get_column_type(int col) const
- {
- return PQftype(m_res, col);
- }
-
- const char* get_value(int row, int col) const
- {
- return PQgetvalue(m_res, row, col);
- }
-
- bool is_null(int row, int col) const
- {
- return PQgetisnull(m_res, row, col);
- }
-
- int length(int row, int col) const
- {
- return PQgetlength(m_res, row, col);
- }
-
- Oid insert_oid() const
- {
- return PQoidValue(m_res);
- }
-
- template<ExecStatusType... Excepted>
- void verify_error()
- {
- if (m_res)
- {
- ExecStatusType got = status();
- if (! in<ExecStatusType, Excepted...>(got))
- throw error(m_res);
- }
- }
-
- template<ExecStatusType... Excepted>
- void verify_error(error& e)
- {
- if (m_res)
- {
- ExecStatusType got = status();
- if (!in<ExecStatusType, Excepted...>(got))
- e = error(m_res);
- }
- }
-
- void clear()
- {
- if (m_res)
- {
- PQclear(m_res);
- m_res = nullptr;
- }
- }
-
-private:
- PGresult* m_res;
-};
-
-class base_statement
-{
- friend class error;
-public:
- explicit base_statement(base_database& db);
- ~base_statement()
- {
- }
- base_statement(const base_statement&) = delete;
- base_statement(base_statement&& src)
- : m_conn(src.m_conn), m_binders(std::move(src.m_binders)), m_res(std::move(src.m_res)), _name(std::move(src._name))
- {
- }
- base_statement& operator=(const base_statement&) = delete;
- base_statement& operator=(base_statement&& src)
- {
- if (this != &src)
- {
- close();
- m_conn = src.m_conn;
- m_binders = std::move(src.m_binders);
- m_res = std::move(src.m_res);
- }
- return *this;
- }
-
- result& get_result() { return m_res; }
-
- void close()
- {
- m_res = nullptr;
- }
-
- uint64_t affetced_rows() const
- {
- return m_res.affected_rows();
- }
-
- void bind_param(size_t index, const char* param, size_t length)
- {
- m_binders[index].bind(param, length);
- }
- template<class Param>
- void bind_param(size_t index, const Param& param)
- {
- m_binders[index].bind(param);
- }
-
- template<class Type>
- void bind_field(size_t index, Type&& value)
- {
- if (m_res.is_null(0, static_cast<int>(index)))
- value = Type();
- else
- value = m_binders[index].get<typename std::remove_const<Type>::type>();
- }
-
- void bind_field(size_t index, char* value, size_t length)
- {
- memcpy(value, m_binders[index].value(), std::min<size_t>(length, m_binders[index].length()));
- }
-
- template<size_t N>
- void bind_field(size_t index, std::array<char, N>&& value)
- {
- bind_field(index, value.data(), value.size());
- }
-
- template<typename T>
- void bind_field(size_t index, bind_string_helper<T>&& value)
- {
- value.assign(m_binders[index].value(), m_binders[index].length());
- }
-
- template<typename Type>
- void bind_field(size_t index, indicator<Type>&& value)
- {
- if (m_res)
- {
- qtl::bind_field(*this, index, value.data);
- value.is_null = m_res.is_null(0, static_cast<int>(index));
- value.length = m_res.length(0, static_cast<int>(index));
- value.is_truncated = m_binders[index].length() < value.length;
- }
- }
-
- void bind_field(size_t index, large_object&& value)
- {
- if (m_res.is_null(0, static_cast<int>(index)))
- value.close();
- else
- value = m_binders[index].get<large_object>(m_conn);
- }
- void bind_field(size_t index, blob_data&& value)
- {
- if (m_res.is_null(0, static_cast<int>(index)))
- {
- value.data = nullptr;
- value.size = 0;
- }
- else
- {
- m_binders[index].get(value);
- }
- }
-
- template<typename... Types>
- void bind_field(size_t index, std::tuple<Types...>&& value)
- {
- if (m_res.is_null(0, static_cast<int>(index)))
- value = std::tuple<Types...>();
- else
- m_binders[index].get(value);
- }
-
-#ifdef _QTL_ENABLE_CPP17
-
- template<typename T>
- inline void bind_field(size_t index, std::optional<T>&& value)
- {
- if (m_res.is_null(0, static_cast<int>(index)))
- {
- value.reset();
- }
- else
- {
- T v;
- bind_field(index, v);
- value = std::move(v);
- }
- }
-
- void bind_field(size_t index, std::any&& value)
- {
- if (m_res.is_null(0, static_cast<int>(index)))
- {
- value = nullptr;
- }
- else
- {
- Oid oid = m_res.get_column_type(index);
- switch (oid)
+ }
+ inline int64_t hton(int64_t v)
{
- case object_traits<bool>::type_id:
- value = field_cast<bool>(index);
- break;
- case object_traits<char>::type_id:
- value = field_cast<char>(index);
- break;
- case object_traits<float>::type_id:
- value = field_cast<float>(index);
- break;
- case object_traits<double>::type_id:
- value = field_cast<double>(index);
- break;
- case object_traits<int16_t>::type_id:
- value = field_cast<int16_t>(index);
- break;
- case object_traits<int32_t>::type_id:
- value = field_cast<int32_t>(index);
- break;
- case object_traits<int64_t>::type_id:
- value = field_cast<int64_t>(index);
- break;
- case object_traits<Oid>::type_id:
- value = field_cast<Oid>(index);
- break;
- case object_traits<std::string>::type_id:
- value = field_cast<std::string>(index);
- break;
- case object_traits<timestamp>::type_id:
- value = field_cast<timestamp>(index);
- break;
- case object_traits<interval>::type_id:
- value = field_cast<interval>(index);
- break;
- case object_traits<date>::type_id:
- value = field_cast<date>(index);
- break;
- case object_traits<std::vector<uint8_t>>::type_id:
- value = field_cast<std::vector<uint8_t>>(index);
- break;
- case object_traits<bool>::array_type_id:
- value = field_cast<std::vector<bool>>(index);
- break;
- case object_traits<char>::array_type_id:
- value = field_cast<std::vector<char>>(index);
- break;
- case object_traits<float>::array_type_id:
- value = field_cast<std::vector<float>>(index);
- break;
- case object_traits<double>::array_type_id:
- value = field_cast<std::vector<double>>(index);
- break;
- case object_traits<int16_t>::array_type_id:
- value = field_cast<std::vector<int16_t>>(index);
- break;
- case object_traits<int32_t>::array_type_id:
- value = field_cast<std::vector<int32_t>>(index);
- break;
- case object_traits<int64_t>::array_type_id:
- value = field_cast<std::vector<int64_t>>(index);
- break;
- case object_traits<Oid>::array_type_id:
- value = field_cast<std::vector<Oid>>(index);
- break;
- case object_traits<std::string>::array_type_id:
- value = field_cast<std::vector<std::string>>(index);
- break;
- case object_traits<timestamp>::array_type_id:
- value = field_cast<std::vector<timestamp>>(index);
- break;
- case object_traits<interval>::array_type_id:
- value = field_cast<std::vector<interval>>(index);
- break;
- case object_traits<date>::array_type_id:
- value = field_cast<std::vector<date>>(index);
- break;
- default:
- throw postgres::error("Unsupported field type");
+ return hton(static_cast<uint64_t>(v));
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_integral<T>::value && !std::is_const<T>::value>::type>
+ inline T &hton_inplace(T &v)
+ {
+ v = hton(v);
+ return v;
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_integral<T>::value && !std::is_const<T>::value>::type>
+ std::pair<std::vector<char>::iterator, size_t> push(std::vector<char> &buffer, T v)
+ {
+ v = hton_inplace(v);
+ char *data = reinterpret_cast<char *>(&v);
+ auto it = buffer.insert(buffer.end(), data, data + sizeof(T));
+ return std::make_pair(it, sizeof(T));
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_integral<T>::value && !std::is_const<T>::value>::type>
+ const char *pop(const char *data, T &v)
+ {
+ v = ntoh(*reinterpret_cast<const T *>(data));
+ return data + sizeof(T);
}
}
- }
-#endif // C++17
+ class base_database;
+ class result;
-protected:
- PGconn* m_conn;
- result m_res;
- std::string _name;
- std::vector<binder> m_binders;
-
- template<ExecStatusType... Excepted>
- void verify_error()
- {
- if (m_res)
- m_res.verify_error<Excepted...>();
- else
- throw error(m_conn);
- }
- void finish(result& res)
- {
- while (res)
+ class error : public std::exception
{
- res = PQgetResult(m_conn);
- }
- }
-
- template<typename T>
- T field_cast(size_t index)
- {
- T v;
- m_binders[index].get(v);
- return v;
- }
-};
-
-class statement : public base_statement
-{
-public:
- explicit statement(base_database& db) : base_statement(db)
- {
- }
- statement(const statement&) = delete;
- statement(statement&& src) : base_statement(std::move(src))
- {
- }
-
- ~statement()
- {
- finish(m_res);
-
- if (!_name.empty())
- {
- std::ostringstream oss;
- oss << "DEALLOCATE " << _name << ";";
- result res = PQexec(m_conn, oss.str().data());
- error e(res.handle());
- }
- }
-
- void open(const char* command, int nParams=0, const Oid *paramTypes=nullptr)
- {
- _name.resize(sizeof(intptr_t) * 2+1);
- int n = sprintf(const_cast<char*>(_name.data()), "q%p", this);
- _name.resize(n);
- std::transform(_name.begin(), _name.end(), _name.begin(), tolower);
- result res = PQprepare(m_conn, _name.data(), command, nParams, paramTypes);
- res.verify_error<PGRES_COMMAND_OK>();
- }
- template<typename... Types>
- void open(const char* command)
- {
- auto binder_list = make_binder_list(Types()...);
- std::array<Oid, sizeof...(Types)> types;
- std::transform(binder_list.begin(), binder_list.end(), types.begin(), [](const binder& b) {
- return b.type();
- });
-
- open(command, types.size(), types.data());
- }
-
- void attach(const char* name)
- {
- result res = PQdescribePrepared(m_conn, name);
- res.verify_error<PGRES_COMMAND_OK>();
- _name = name;
- }
-
- void execute()
- {
- if(!PQsendQueryPrepared(m_conn, _name.data(), 0, nullptr, nullptr, nullptr, 1))
- throw error(m_conn);
- if (!PQsetSingleRowMode(m_conn))
- throw error(m_conn);
- m_res = PQgetResult(m_conn);
- verify_error<PGRES_COMMAND_OK, PGRES_SINGLE_TUPLE>();
- }
-
- template<typename Types>
- void execute(const Types& params)
- {
- const size_t count = qtl::params_binder<statement, Types>::size;
- if (count > 0)
- {
- m_binders.resize(count);
- qtl::bind_params(*this, params);
-
- std::array<const char*, count> values;
- std::array<int, count> lengths;
- std::array<int, count> formats;
- for (size_t i = 0; i != m_binders.size(); i++)
+ public:
+ error() : m_errmsg() {}
+ explicit error(PGconn *conn, PGVerbosity verbosity = PQERRORS_DEFAULT, PGContextVisibility show_context = PQSHOW_CONTEXT_ERRORS)
{
- values[i] = m_binders[i].value();
- lengths[i] = static_cast<int>(m_binders[i].length());
- formats[i] = 1;
+ // PQsetErrorVerbosity(conn, verbosity);
+ // PQsetErrorContextVisibility(conn, show_context);
+ const char *errmsg = PQerrorMessage(conn);
+ if (errmsg)
+ m_errmsg = errmsg;
+ else
+ m_errmsg.clear();
}
- if (!PQsendQueryPrepared(m_conn, _name.data(), static_cast<int>(m_binders.size()), values.data(), lengths.data(), formats.data(), 1))
- throw error(m_conn);
- }
- else
- {
- if (!PQsendQueryPrepared(m_conn, _name.data(), 0, nullptr, nullptr, nullptr, 1))
- throw error(m_conn);
- }
- if (!PQsetSingleRowMode(m_conn))
- throw error(m_conn);
- m_res = PQgetResult(m_conn);
- verify_error<PGRES_COMMAND_OK, PGRES_SINGLE_TUPLE, PGRES_TUPLES_OK>();
- }
- template<typename Types>
- bool fetch(Types&& values)
- {
- if (m_res)
- {
- ExecStatusType status = m_res.status();
- if (status == PGRES_SINGLE_TUPLE)
+ explicit error(PGresult *res)
{
- int count = m_res.get_column_count();
- if (count > 0)
+ const char *errmsg = PQresultErrorMessage(res);
+ if (errmsg)
+ m_errmsg = errmsg;
+ else
+ m_errmsg.clear();
+ }
+
+ explicit error(const char *errmsg) : m_errmsg(errmsg) {}
+
+ virtual const char *what() const NOEXCEPT override { return m_errmsg.data(); }
+ operator bool() const { return !m_errmsg.empty(); }
+
+ protected:
+ std::string m_errmsg;
+ };
+
+ class timeout : public error
+ {
+ public:
+ timeout()
+ {
+ m_errmsg = "timeout";
+ }
+ };
+
+ inline void verify_pgtypes_error(int ret)
+ {
+ if (ret && errno != 0)
+ throw std::system_error(std::error_code(errno, std::generic_category()));
+ }
+
+ struct interval
+ {
+ ::interval *value;
+
+ interval()
+ {
+ value = PGTYPESinterval_new();
+ }
+ explicit interval(char *str)
+ {
+ value = PGTYPESinterval_from_asc(str, nullptr);
+ }
+ interval(const interval &src) : interval()
+ {
+ verify_pgtypes_error(PGTYPESinterval_copy(src.value, value));
+ }
+ interval(interval &&src)
+ {
+ value = src.value;
+ src.value = PGTYPESinterval_new();
+ }
+ ~interval()
+ {
+ PGTYPESinterval_free(value);
+ }
+
+ std::string to_string() const
+ {
+ return PGTYPESinterval_to_asc(value);
+ }
+
+ interval &operator=(const interval &src)
+ {
+ if (&src != this)
+ verify_pgtypes_error(PGTYPESinterval_copy(src.value, value));
+ return *this;
+ }
+ };
+
+ struct timestamp
+ {
+ ::timestamp value;
+
+ timestamp() = default;
+
+ static timestamp now()
+ {
+ timestamp result;
+ PGTYPEStimestamp_current(&result.value);
+ return result;
+ }
+ explicit timestamp(char *str)
+ {
+ value = PGTYPEStimestamp_from_asc(str, nullptr);
+ verify_pgtypes_error(1);
+ }
+
+ int format(char *str, int n, const char *format) const
+ {
+ timestamp temp = *this;
+ return PGTYPEStimestamp_fmt_asc(&temp.value, str, n, format);
+ }
+ static timestamp parse(char *str, const char *format)
+ {
+ timestamp result;
+ verify_pgtypes_error(PGTYPEStimestamp_defmt_asc(str, format, &result.value));
+ return result;
+ }
+
+ std::string to_string() const
+ {
+ char *str = PGTYPEStimestamp_to_asc(value);
+ std::string result = str;
+ PGTYPESchar_free(str);
+ return result;
+ }
+
+ timestamp &operator+=(const interval &span)
+ {
+ verify_pgtypes_error(PGTYPEStimestamp_add_interval(&value, span.value, &value));
+ return *this;
+ }
+
+ timestamp &operator-=(const interval &span)
+ {
+ verify_pgtypes_error(PGTYPEStimestamp_sub_interval(&value, span.value, &value));
+ return *this;
+ }
+ };
+
+ inline timestamp operator+(const timestamp &a, const interval &b)
+ {
+ timestamp result = a;
+ return result += b;
+ }
+
+ inline timestamp operator-(const timestamp &a, const interval &b)
+ {
+ timestamp result = a;
+ result -= b;
+ return result;
+ }
+
+ struct timestamptz
+ {
+ ::TimestampTz value;
+ /*
+ timestamptz() = default;
+ explicit timestamptz(pg_time_t v)
+ {
+ value = (TimestampTz)v -
+ ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);
+ value *= USECS_PER_SEC;
+ }
+
+ static timestamptz now()
+ {
+ timestamptz result;
+ auto tp = std::chrono::system_clock::now();
+ int sec = tp.time_since_epoch().count()*std::nano::num/std::nano::den;
+ int usec = tp.time_since_epoch().count()*std::nano::num % std::nano::den;
+
+ result.value = (TimestampTz)sec -
+ ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);
+ result.value = (result.value * USECS_PER_SEC) + usec;
+
+ return result;
+ }
+ */
+ };
+
+ struct date
+ {
+ ::date value;
+
+ date() = default;
+ explicit date(timestamp dt)
+ {
+ value = PGTYPESdate_from_timestamp(dt.value);
+ }
+ explicit date(char *str)
+ {
+ value = PGTYPESdate_from_asc(str, nullptr);
+ verify_pgtypes_error(1);
+ }
+ explicit date(int year, int month, int day)
+ {
+ int mdy[3] = {month, day, year};
+ PGTYPESdate_mdyjul(mdy, &value);
+ }
+
+ std::string to_string() const
+ {
+ char *str = PGTYPESdate_to_asc(value);
+ std::string result = str;
+ PGTYPESchar_free(str);
+ return str;
+ }
+
+ static date now()
+ {
+ date result;
+ PGTYPESdate_today(&result.value);
+ return result;
+ }
+
+ static date parse(char *str, const char *format)
+ {
+ date result;
+ verify_pgtypes_error(PGTYPESdate_defmt_asc(&result.value, format, str));
+ return result;
+ }
+
+ std::string format(const char *format)
+ {
+ std::string result;
+ result.resize(128);
+ verify_pgtypes_error(PGTYPESdate_fmt_asc(value, format, const_cast<char *>(result.data())));
+ result.resize(strlen(result.data()));
+ return result;
+ }
+
+ std::tuple<int, int, int> get_date()
+ {
+ int mdy[3];
+ PGTYPESdate_julmdy(value, mdy);
+ return std::make_tuple(mdy[2], mdy[0], mdy[1]);
+ }
+
+ int dayofweek()
+ {
+ return PGTYPESdate_dayofweek(value);
+ }
+ };
+
+ struct decimal
+ {
+ ::decimal value;
+ };
+
+ struct numeric
+ {
+ ::numeric *value;
+
+ numeric()
+ {
+ value = PGTYPESnumeric_new();
+ }
+ numeric(int v) : numeric()
+ {
+ verify_pgtypes_error(PGTYPESnumeric_from_int(v, value));
+ }
+ numeric(long v) : numeric()
+ {
+ verify_pgtypes_error(PGTYPESnumeric_from_long(v, value));
+ }
+ numeric(double v) : numeric()
+ {
+ verify_pgtypes_error(PGTYPESnumeric_from_double(v, value));
+ }
+ numeric(const decimal &v) : numeric()
+ {
+ verify_pgtypes_error(PGTYPESnumeric_from_decimal(const_cast<::decimal *>(&v.value), value));
+ }
+ numeric(const numeric &src) : numeric()
+ {
+ verify_pgtypes_error(PGTYPESnumeric_copy(src.value, value));
+ }
+ explicit numeric(const char *str)
+ {
+ value = PGTYPESnumeric_from_asc(const_cast<char *>(str), nullptr);
+ }
+ ~numeric()
+ {
+ PGTYPESnumeric_free(value);
+ }
+
+ operator double() const
+ {
+ double result;
+ verify_pgtypes_error(PGTYPESnumeric_to_double(value, &result));
+ return result;
+ }
+
+ operator int() const
+ {
+ int result;
+ verify_pgtypes_error(PGTYPESnumeric_to_int(value, &result));
+ return result;
+ }
+
+ operator long() const
+ {
+ long result;
+ verify_pgtypes_error(PGTYPESnumeric_to_long(value, &result));
+ return result;
+ }
+
+ operator decimal() const
+ {
+ decimal result;
+ verify_pgtypes_error(PGTYPESnumeric_to_decimal(value, &result.value));
+ return result;
+ }
+
+ int compare(const numeric &other) const
+ {
+ return PGTYPESnumeric_cmp(value, other.value);
+ }
+
+ inline numeric &operator+=(const numeric &b)
+ {
+ verify_pgtypes_error(PGTYPESnumeric_add(value, b.value, value));
+ return *this;
+ }
+
+ inline numeric &operator-=(const numeric &b)
+ {
+ verify_pgtypes_error(PGTYPESnumeric_sub(value, b.value, value));
+ return *this;
+ }
+
+ inline numeric &operator*=(const numeric &b)
+ {
+ verify_pgtypes_error(PGTYPESnumeric_mul(value, b.value, value));
+ return *this;
+ }
+
+ inline numeric &operator/=(const numeric &b)
+ {
+ verify_pgtypes_error(PGTYPESnumeric_div(value, b.value, value));
+ return *this;
+ }
+
+ std::string to_string(int dscale = -1) const
+ {
+ char *str = PGTYPESnumeric_to_asc(value, dscale);
+ std::string result = str;
+ PGTYPESchar_free(str);
+ return result;
+ }
+ };
+
+ inline numeric operator+(const numeric &a, const numeric &b)
+ {
+ numeric result;
+ verify_pgtypes_error(PGTYPESnumeric_add(a.value, b.value, result.value));
+ return result;
+ }
+
+ inline numeric operator-(const numeric &a, const numeric &b)
+ {
+ numeric result;
+ verify_pgtypes_error(PGTYPESnumeric_sub(a.value, b.value, result.value));
+ return result;
+ }
+
+ inline numeric operator*(const numeric &a, const numeric &b)
+ {
+ numeric result;
+ verify_pgtypes_error(PGTYPESnumeric_mul(a.value, b.value, result.value));
+ return result;
+ }
+
+ inline numeric operator/(const numeric &a, const numeric &b)
+ {
+ numeric result;
+ verify_pgtypes_error(PGTYPESnumeric_div(a.value, b.value, result.value));
+ return result;
+ }
+
+ inline bool operator==(const numeric &a, const numeric &b)
+ {
+ return a.compare(b) == 0;
+ }
+
+ inline bool operator<(const numeric &a, const numeric &b)
+ {
+ return a.compare(b) < 0;
+ }
+
+ inline bool operator>(const numeric &a, const numeric &b)
+ {
+ return a.compare(b) > 0;
+ }
+
+ inline bool operator<=(const numeric &a, const numeric &b)
+ {
+ return a.compare(b) <= 0;
+ }
+
+ inline bool operator>=(const numeric &a, const numeric &b)
+ {
+ return a.compare(b) >= 0;
+ }
+
+ inline bool operator!=(const numeric &a, const numeric &b)
+ {
+ return a.compare(b) != 0;
+ }
+
+ class large_object : public qtl::blobbuf
+ {
+ public:
+ large_object() : m_conn(nullptr), m_id(InvalidOid), m_fd(-1) {}
+ large_object(PGconn *conn, Oid loid, std::ios_base::openmode mode)
+ {
+ open(conn, loid, mode);
+ }
+ large_object(const large_object &) = delete;
+ large_object(large_object &&src)
+ {
+ swap(src);
+ src.m_conn = nullptr;
+ src.m_fd = -1;
+ }
+ ~large_object()
+ {
+ close();
+ }
+
+ static large_object create(PGconn *conn, Oid loid = InvalidOid)
+ {
+ Oid oid = lo_create(conn, loid);
+ if (oid == InvalidOid)
+ throw error(conn);
+ return large_object(conn, oid, std::ios::in | std::ios::out | std::ios::binary);
+ }
+ static large_object load(PGconn *conn, const char *filename, Oid loid = InvalidOid)
+ {
+ Oid oid = lo_import_with_oid(conn, filename, loid);
+ if (oid == InvalidOid)
+ throw error(conn);
+ return large_object(conn, oid, std::ios::in | std::ios::out | std::ios::binary);
+ }
+ void save(const char *filename) const
+ {
+ if (lo_export(m_conn, m_id, filename) < 0)
+ throw error(m_conn);
+ }
+
+ void unlink()
+ {
+ close();
+ if (lo_unlink(m_conn, m_id) < 0)
+ throw error(m_conn);
+ }
+
+ large_object &operator=(const large_object &) = delete;
+ large_object &operator=(large_object &&src)
+ {
+ if (this != &src)
{
- m_binders.resize(count);
- for (int i = 0; i != count; i++)
- {
- m_binders[i]=binder(m_res.get_value(0, i), m_res.length(0, i),
- m_res.get_column_type(i));
- }
- qtl::bind_record(*this, std::forward<Types>(values));
+ swap(src);
+ src.close();
}
- m_res = PQgetResult(m_conn);
- return true;
+ return *this;
}
- else
+ bool is_open() const { return m_fd >= 0; }
+ Oid oid() const { return m_id; }
+
+ void open(PGconn *conn, Oid loid, std::ios_base::openmode mode)
{
- verify_error<PGRES_TUPLES_OK>();
- }
- }
- return false;
- }
+ int lomode = 0;
+ if (mode & std::ios_base::in)
+ lomode |= INV_READ;
+ if (mode & std::ios_base::out)
+ lomode |= INV_WRITE;
+ m_conn = conn;
+ m_id = loid;
+ m_fd = lo_open(m_conn, loid, lomode);
+ if (m_fd < 0)
+ throw error(m_conn);
- bool next_result()
- {
- m_res = PQgetResult(m_conn);
- return m_res && m_res.status() == PGRES_SINGLE_TUPLE;
- }
-
- void reset()
- {
- finish(m_res);
- m_res.clear();
- }
-};
-
-class base_database
-{
-protected:
- base_database()
- {
- m_conn = nullptr;
- }
-
-public:
- typedef postgres::error exception_type;
-
- base_database(const base_database&) = delete;
- base_database(base_database&& src)
- {
- m_conn = src.m_conn;
- src.m_conn = nullptr;
- }
-
- ~base_database()
- {
- if (m_conn)
- PQfinish(m_conn);
- }
-
- base_database& operator=(const base_database&) = delete;
- base_database& operator=(base_database&& src)
- {
- if (this != &src)
- {
- if (m_conn)
- PQfinish(m_conn);
- m_conn = src.m_conn;
- src.m_conn = nullptr;
- }
- return *this;
- }
-
- const char* errmsg() const
- {
- return PQerrorMessage(m_conn);
- }
-
- PGconn* handle() { return m_conn; }
-
- const char* encoding() const
- {
- int encoding = PQclientEncoding(m_conn);
- return (encoding >= 0) ? pg_encoding_to_char(encoding) : nullptr;
- }
-
- void encoding(const char* encoding)
- {
- if (PQsetClientEncoding(m_conn, encoding))
- throw error(m_conn);
- }
-
- void trace(FILE* stream)
- {
- PQtrace(m_conn, stream);
- }
- void untrace()
- {
- PQuntrace(m_conn);
- }
-
- const char* current() const
- {
- return PQdb(m_conn);
- }
-
- const char* user() const
- {
- return PQuser(m_conn);
- }
-
- const char* host() const
- {
- return PQhost(m_conn);
- }
-
- const char* password() const
- {
- return PQpass(m_conn);
- }
-
- const char* port() const
- {
- return PQport(m_conn);
- }
-
- const char* options() const
- {
- return PQoptions(m_conn);
- }
-
- ConnStatusType status() const
- {
- return PQstatus(m_conn);
- }
-
- PGTransactionStatusType transactionStatus() const
- {
- return PQtransactionStatus(m_conn);
- }
-
- const char* parameterStatus(const char *paramName) const
- {
- return PQparameterStatus(m_conn, paramName);
- }
-
- void reset()
- {
- if(status() == CONNECTION_BAD)
- PQreset(m_conn);
- }
-
- void close()
- {
- PQfinish(m_conn);
- m_conn = nullptr;
- }
-
-protected:
- PGconn* m_conn;
- void throw_exception() { throw postgres::error(m_conn); }
-};
-
-class simple_statment : public base_statement
-{
-public:
- simple_statment(base_database& db, qtl::postgres::result&& res) : base_statement(db)
- {
- m_res = std::move(res);
- }
-
- template<typename ValueProc>
- void fetch_all(ValueProc& proc)
- {
- int row_count = PQntuples(m_res.handle());
- if (row_count > 0)
- {
- int col_count = m_res.get_column_count();
- m_binders.resize(col_count);
- auto values = qtl::detail::make_values(proc);
- for (int i = 0; i != row_count; i++)
- {
- for (int j = 0; j != col_count; j++)
+ m_size = size();
+ init_buffer(mode);
+ if (mode & std::ios_base::trunc)
{
- m_binders[j] = binder(m_res.get_value(i, j), m_res.length(i, j),
- m_res.get_column_type(j));
- }
- qtl::bind_record(*this, std::forward<decltype(values)>(values));
- qtl::detail::apply(proc, std::forward<decltype(values)>(values));
- }
- }
- }
-};
-
-class database : public base_database, public qtl::base_database<database, statement>
-{
-public:
- database() = default;
-
- bool open(const std::map<std::string, std::string>& params, bool expand_dbname = false)
- {
- std::vector<const char*> keywords(params.size()+1);
- std::vector<const char*> values(params.size()+1);
- for (auto& param : params)
- {
- keywords.push_back(param.first.data());
- values.push_back(param.second.data());
- }
- keywords.push_back(nullptr);
- values.push_back(nullptr);
- m_conn = PQconnectdbParams(keywords.data(), values.data(), expand_dbname);
- return m_conn != nullptr && status()== CONNECTION_OK;
- }
-
- bool open(const char * conninfo)
- {
- m_conn = PQconnectdb(conninfo);
- return m_conn != nullptr && status() == CONNECTION_OK;
- }
-
- bool open(const char* host, const char* user, const char* password,
- unsigned short port = 5432, const char* db = "postgres", const char* options = nullptr)
- {
- char port_text[16];
- sprintf(port_text, "%u", port);
- m_conn = PQsetdbLogin(host, port_text, options, nullptr, db, user, password);
- return m_conn != nullptr && status() == CONNECTION_OK;
- }
-
- statement open_command(const char* query_text, size_t /*text_length*/)
- {
- statement stmt(*this);
- stmt.open(query_text);
- return stmt;
- }
- statement open_command(const char* query_text)
- {
- return open_command(query_text, 0);
- }
- statement open_command(const std::string& query_text)
- {
- return open_command(query_text.data());
- }
-
- void simple_execute(const char* query_text, uint64_t* paffected = nullptr)
- {
- qtl::postgres::result res(PQexec(m_conn, query_text));
- if (!res) throw_exception();
- res.verify_error<PGRES_COMMAND_OK, PGRES_TUPLES_OK>();
- if (paffected) *paffected = res.affected_rows();
- }
- template<typename ValueProc>
- void simple_query(const char* query_text, ValueProc&& proc)
- {
- qtl::postgres::result res(PQexec(m_conn, query_text));
- if (!res) throw_exception();
- res.verify_error<PGRES_COMMAND_OK, PGRES_TUPLES_OK>();
- if (res.status() == PGRES_TUPLES_OK)
- {
- simple_statment stmt(*this, std::move(res));
- stmt.fetch_all(std::forward<ValueProc>(proc));
- }
- }
-
- void auto_commit(bool on)
- {
- if(on)
- simple_execute("SET AUTOCOMMIT TO ON");
- else
- simple_execute("SET AUTOCOMMIT TO OFF");
- }
-
- void begin_transaction()
- {
- simple_execute("BEGIN");
- }
- void rollback()
- {
- simple_execute("ROLLBACK");
- }
- void commit()
- {
- simple_execute("COMMIT");
- }
-
- bool is_alive()
- {
- qtl::postgres::result res(PQexec(m_conn, ""));
- return res && res.status() == PGRES_COMMAND_OK;
- }
-
-};
-
-inline int event_flags(PostgresPollingStatusType status)
-{
- int flags = 0;
- if (status == PGRES_POLLING_READING)
- flags |= event::ef_read;
- else if (status == PGRES_POLLING_WRITING)
- flags |= event::ef_write;
- else if (status == PGRES_POLLING_FAILED)
- flags |= event::ef_exception;
- return flags;
-}
-
-class async_connection;
-
-template<typename Handler>
-inline void async_wait(qtl::event* event, PGconn* conn, int timeout, Handler&& handler)
-{
- int flushed = PQflush(conn);
- if (flushed < 0)
- {
- handler(error(conn));
- return;
- }
- if (flushed == 1)
- {
- event->set_io_handler(qtl::event::ef_read | qtl::event::ef_write, timeout,
- [event, conn, timeout, handler](int flags) mutable {
- if (flags&qtl::event::ef_timeout)
- {
- handler(postgres::timeout());
- return;
- }
- if (flags&qtl::event::ef_read)
- {
- if (!PQconsumeInput(conn))
- {
- handler(error(conn));
- return;
+ if (lo_truncate(m_conn, m_fd, 0) < 0)
+ throw error(m_conn);
}
}
- if (flags&(qtl::event::ef_read | qtl::event::ef_write | event::ef_exception))
- async_wait(event, conn, timeout, handler);
- });
- }
- else
- {
- event->set_io_handler(qtl::event::ef_read, 10,
- [event, conn, timeout, handler](int flags) mutable {
- if (flags&qtl::event::ef_timeout)
+
+ void close()
{
- handler(postgres::timeout());
- }
- else if (flags&(qtl::event::ef_read | qtl::event::ef_exception))
- {
- if (PQconsumeInput(conn))
+ if (m_fd >= 0)
{
- if (!PQisBusy(conn))
- handler(postgres::error());
- else
- async_wait(event, conn, timeout, handler);
+ overflow();
+ if (lo_close(m_conn, m_fd) < 0)
+ throw error(m_conn);
+ m_fd = -1;
+ }
+ }
+
+ void flush()
+ {
+ if (m_fd >= 0)
+ overflow();
+ }
+
+ size_t size() const
+ {
+ pg_int64 size = 0;
+ if (m_fd >= 0)
+ {
+ pg_int64 org = lo_tell64(m_conn, m_fd);
+ size = lo_lseek64(m_conn, m_fd, 0, SEEK_END);
+ lo_lseek64(m_conn, m_fd, org, SEEK_SET);
+ }
+ return size;
+ }
+
+ void resize(size_t n)
+ {
+ if (m_fd >= 0 && lo_truncate64(m_conn, m_fd, n) < 0)
+ throw error(m_conn);
+ }
+
+ void swap(large_object &other)
+ {
+ std::swap(m_conn, other.m_conn);
+ std::swap(m_id, other.m_id);
+ std::swap(m_fd, other.m_fd);
+ qtl::blobbuf::swap(other);
+ }
+
+ protected:
+ enum
+ {
+ default_buffer_size = 4096
+ };
+
+ virtual bool read_blob(char *buffer, off_type &count, pos_type position) override
+ {
+ return lo_lseek64(m_conn, m_fd, position, SEEK_SET) >= 0 && lo_read(m_conn, m_fd, buffer, count) > 0;
+ }
+ virtual void write_blob(const char *buffer, size_t count) override
+ {
+ if (lo_write(m_conn, m_fd, buffer, count) < 0)
+ throw error(m_conn);
+ }
+
+ private:
+ PGconn *m_conn;
+ Oid m_id;
+ int m_fd;
+ };
+
+ struct array_header
+ {
+ int32_t ndim;
+ int32_t flags;
+ int32_t elemtype;
+ struct dimension
+ {
+ int32_t length;
+ int32_t lower_bound;
+ } dims[1];
+ };
+
+ /*
+ template<typename T>
+ struct oid_traits
+ {
+ typedef T value_type;
+ static Oid type_id;
+ static Oid array_type_id; //optional
+ static const char* get(value_type& result, const char* begin, const char* end);
+ static std::pair<const char*, size_t> data(const T& v, std::vector<char*>& buffer);
+ };
+ */
+
+ template <typename T, Oid id>
+ struct base_object_traits
+ {
+ typedef T value_type;
+ enum
+ {
+ type_id = id
+ };
+ static bool is_match(Oid v)
+ {
+ return v == type_id;
+ }
+ };
+
+ template <typename T>
+ struct object_traits;
+
+#define QTL_POSTGRES_SIMPLE_TRAITS(T, oid, array_oid) \
+ template <> \
+ struct object_traits<T> : public base_object_traits<T, oid> \
+ { \
+ enum \
+ { \
+ array_type_id = array_oid \
+ }; \
+ static const char *get(value_type &result, const char *data, const char *end) \
+ { \
+ result = *reinterpret_cast<const value_type *>(data); \
+ return data + sizeof(value_type); \
+ } \
+ static std::pair<const char *, size_t> data(const T &v, std::vector<char> & /*data*/) \
+ { \
+ return std::make_pair(reinterpret_cast<const char *>(&v), sizeof(T)); \
+ } \
+ };
+
+ QTL_POSTGRES_SIMPLE_TRAITS(bool, BOOLOID, 1000)
+ QTL_POSTGRES_SIMPLE_TRAITS(char, CHAROID, 1002)
+ QTL_POSTGRES_SIMPLE_TRAITS(float, FLOAT4OID, FLOAT4ARRAYOID)
+ QTL_POSTGRES_SIMPLE_TRAITS(double, FLOAT8OID, 1022)
+
+ template <typename T, Oid id, Oid array_id>
+ struct integral_traits : public base_object_traits<T, id>
+ {
+ enum
+ {
+ array_type_id = array_id
+ };
+ typedef typename base_object_traits<T, id>::value_type value_type;
+ static const char *get(value_type &v, const char *data, const char *end)
+ {
+ return detail::pop(data, v);
+ }
+ static std::pair<const char *, size_t> data(value_type v, std::vector<char> &buffer)
+ {
+ size_t n = buffer.size();
+ detail::push(buffer, v);
+ return std::make_pair(buffer.data() + n, buffer.size() - n);
+ }
+ };
+
+ template <>
+ struct object_traits<int16_t> : public integral_traits<int16_t, INT2OID, INT2ARRAYOID>
+ {
+ };
+
+ template <>
+ struct object_traits<int32_t> : public integral_traits<int32_t, INT4OID, INT4ARRAYOID>
+ {
+ };
+
+ template <>
+ struct object_traits<int64_t> : public integral_traits<int64_t, INT8OID, 1016>
+ {
+ };
+
+ template <>
+ struct object_traits<Oid> : public integral_traits<Oid, OIDOID, OIDARRAYOID>
+ {
+ };
+
+ template <typename T>
+ struct text_traits : public base_object_traits<T, TEXTOID>
+ {
+ enum
+ {
+ array_type_id = TEXTARRAYOID
+ };
+ };
+
+ template <>
+ struct object_traits<const char *> : public text_traits<const char *>
+ {
+ static bool is_match(Oid v)
+ {
+ return v == TEXTOID || v == VARCHAROID || v == BPCHAROID;
+ }
+ static const char *get(const char *&result, const char *data, const char *end)
+ {
+ result = data;
+ return end;
+ }
+ static std::pair<const char *, size_t> data(const char *v, std::vector<char> & /*buffer*/)
+ {
+ return std::make_pair(v, strlen(v));
+ }
+ };
+
+ template <>
+ struct object_traits<char *> : public object_traits<const char *>
+ {
+ };
+
+ template <>
+ struct object_traits<std::string> : public text_traits<std::string>
+ {
+ static bool is_match(Oid v)
+ {
+ return v == TEXTOID || v == VARCHAROID || v == BPCHAROID;
+ }
+ static const char *get(value_type &result, const char *data, const char *end)
+ {
+ result.assign(data, end);
+ return end;
+ }
+ static std::pair<const char *, size_t> data(const std::string &v, std::vector<char> & /*buffer*/)
+ {
+ return std::make_pair(v.data(), v.size());
+ }
+ };
+
+ template <>
+ struct object_traits<timestamp> : public base_object_traits<timestamp, TIMESTAMPOID>
+ {
+ enum
+ {
+ array_type_id = TIMESTAMPOID + 1
+ };
+ static const char *get(value_type &result, const char *data, const char *end)
+ {
+ result = *reinterpret_cast<const timestamp *>(data);
+ result.value = detail::ntoh(result.value);
+ return data + sizeof(timestamp);
+ }
+ static std::pair<const char *, size_t> data(const timestamp &v, std::vector<char> &buffer)
+ {
+ size_t n = buffer.size();
+ detail::push(buffer, v.value);
+ return std::make_pair(buffer.data() + n, buffer.size() - n);
+ }
+ };
+
+ template <>
+ struct object_traits<timestamptz> : public base_object_traits<timestamptz, TIMESTAMPTZOID>
+ {
+ enum
+ {
+ array_type_id = TIMESTAMPTZOID + 1
+ };
+ static const char *get(value_type &result, const char *data, const char *end)
+ {
+ result = *reinterpret_cast<const timestamptz *>(data);
+ result.value = detail::ntoh(result.value);
+ return data + sizeof(timestamptz);
+ }
+ static std::pair<const char *, size_t> data(const timestamptz &v, std::vector<char> &buffer)
+ {
+ size_t n = buffer.size();
+ detail::push(buffer, v.value);
+ return std::make_pair(buffer.data() + n, buffer.size() - n);
+ }
+ };
+
+ template <>
+ struct object_traits<interval> : public base_object_traits<interval, INTERVALOID>
+ {
+ enum
+ {
+ array_type_id = INTERVALOID + 1
+ };
+ static const char *get(value_type &result, const char *data, const char *end)
+ {
+ const ::interval *value = reinterpret_cast<const ::interval *>(data);
+ result.value->time = detail::ntoh(value->time);
+ result.value->month = detail::ntoh(value->month);
+ return data + sizeof(interval);
+ }
+ static std::pair<const char *, size_t> data(const interval &v, std::vector<char> &buffer)
+ {
+ size_t n = buffer.size();
+ detail::push(buffer, v.value->time);
+ detail::push(buffer, v.value->month);
+ return std::make_pair(buffer.data() + n, buffer.size() - n);
+ }
+ };
+
+ template <>
+ struct object_traits<date> : public base_object_traits<date, DATEOID>
+ {
+ enum
+ {
+ array_type_id = 1182
+ };
+ static const char *get(value_type &result, const char *data, const char *end)
+ {
+ result = *reinterpret_cast<const date *>(data);
+ result.value = detail::ntoh(result.value);
+ return data + sizeof(date);
+ }
+ static std::pair<const char *, size_t> data(const date &v, std::vector<char> &buffer)
+ {
+ size_t n = buffer.size();
+ detail::push(buffer, v.value);
+ return std::make_pair(buffer.data() + n, buffer.size() - n);
+ }
+ };
+
+ template <typename T>
+ struct bytea_traits : public base_object_traits<T, BYTEAOID>
+ {
+ enum
+ {
+ array_type_id = 1001
+ };
+ };
+
+ template <>
+ struct object_traits<qtl::const_blob_data> : public bytea_traits<qtl::const_blob_data>
+ {
+ static const char *get(value_type &result, const char *data, const char *end)
+ {
+ result.data = data;
+ result.size = end - data;
+ return end;
+ }
+ static std::pair<const char *, size_t> data(const qtl::const_blob_data &v, std::vector<char> & /*buffer*/)
+ {
+ assert(v.size <= UINT32_MAX);
+ return std::make_pair(static_cast<const char *>(v.data), v.size);
+ }
+ };
+
+ template <>
+ struct object_traits<qtl::blob_data> : public bytea_traits<qtl::blob_data>
+ {
+ static const char *get(qtl::blob_data &value, const char *data, const char *end)
+ {
+ if (value.size < end - data)
+ throw std::out_of_range("no enough buffer to receive blob data.");
+ memcpy(value.data, data, end - data);
+ return end;
+ }
+ static std::pair<const char *, size_t> data(const qtl::blob_data &v, std::vector<char> & /*buffer*/)
+ {
+ assert(v.size <= UINT32_MAX);
+ return std::make_pair(static_cast<char *>(v.data), v.size);
+ }
+ };
+
+ template <>
+ struct object_traits<std::vector<uint8_t>> : public bytea_traits<std::vector<uint8_t>>
+ {
+ static const char *get(value_type &result, const char *data, const char *end)
+ {
+ result.assign(data, end);
+ return end;
+ }
+ static std::pair<const char *, size_t> data(const std::vector<uint8_t> &v, std::vector<char> & /*buffer*/)
+ {
+ assert(v.size() <= UINT32_MAX);
+ return std::make_pair(reinterpret_cast<const char *>(v.data()), v.size());
+ }
+ };
+
+ template <>
+ struct object_traits<large_object> : public base_object_traits<large_object, OIDOID>
+ {
+ enum
+ {
+ array_type_id = OIDARRAYOID
+ };
+ static value_type get(PGconn *conn, const char *data, const char *end)
+ {
+ int32_t oid;
+ object_traits<int32_t>::get(oid, data, end);
+ return large_object(conn, oid, std::ios::in | std::ios::out | std::ios::binary);
+ }
+ static std::pair<const char *, size_t> data(const large_object &v, std::vector<char> &buffer)
+ {
+ return object_traits<int32_t>::data(v.oid(), buffer);
+ }
+ };
+
+ template <typename T, Oid id>
+ struct vector_traits : public base_object_traits<std::vector<T>, id>
+ {
+ typedef typename base_object_traits<std::vector<T>, id>::value_type value_type;
+ static const char *get(value_type &result, const char *data, const char *end)
+ {
+ if (end - data < sizeof(array_header))
+ throw std::overflow_error("insufficient data left in message");
+
+ array_header header = *reinterpret_cast<const array_header *>(data);
+ detail::ntoh_inplace(header.ndim);
+ detail::ntoh_inplace(header.flags);
+ detail::ntoh_inplace(header.elemtype);
+ detail::ntoh_inplace(header.dims[0].length);
+ detail::ntoh_inplace(header.dims[0].lower_bound);
+ if (header.ndim != 1 || !object_traits<T>::is_match(header.elemtype))
+ throw std::bad_cast();
+
+ data += sizeof(array_header);
+ result.reserve(header.dims[0].length);
+
+ for (int32_t i = 0; i != header.dims[0].length; i++)
+ {
+ int32_t size;
+ T value;
+ data = detail::pop(data, size);
+ if (end - data < size)
+ throw std::overflow_error("insufficient data left in message");
+ data = object_traits<T>::get(value, data, data + size);
+ if (data > end)
+ throw std::overflow_error("insufficient data left in message");
+ result.push_back(value);
+ }
+ return data;
+ }
+ static std::pair<const char *, size_t> data(const std::vector<T> &v, std::vector<char> &buffer)
+ {
+ assert(v.size() <= INT32_MAX);
+ size_t n = buffer.size();
+ buffer.resize(n + sizeof(array_header));
+ array_header *header = reinterpret_cast<array_header *>(buffer.data() + n);
+ header->ndim = detail::hton(1);
+ header->flags = detail::hton(0);
+ header->elemtype = detail::hton(static_cast<int32_t>(object_traits<T>::type_id));
+ header->dims[0].length = detail::hton(static_cast<int32_t>(v.size()));
+ header->dims[0].lower_bound = detail::hton(1);
+
+ std::vector<char> temp;
+ for (const T &e : v)
+ {
+ std::pair<const char *, size_t> blob = object_traits<T>::data(e, temp);
+ detail::push(buffer, static_cast<int32_t>(blob.second));
+ buffer.insert(buffer.end(), blob.first, blob.first + blob.second);
+ }
+ return std::make_pair(buffer.data() + n, buffer.size() - n);
+ }
+ };
+
+ template <typename Iterator, Oid id>
+ struct iterator_traits : public base_object_traits<Iterator, id>
+ {
+ static const char *get(Iterator first, Iterator last, const char *data, const char *end)
+ {
+ if (end - data < sizeof(array_header))
+ throw std::overflow_error("insufficient data left in message");
+
+ array_header header = *reinterpret_cast<const array_header *>(data);
+ detail::ntoh_inplace(header.ndim);
+ detail::ntoh_inplace(header.flags);
+ detail::ntoh_inplace(header.elemtype);
+ detail::ntoh_inplace(header.dims[0].length);
+ detail::ntoh_inplace(header.dims[0].lower_bound);
+ if (header.ndim != 1 || !object_traits<typename std::iterator_traits<Iterator>::value_type>::is_match(header.elemtype))
+ throw std::bad_cast();
+
+ data += sizeof(array_header);
+ if (std::distance(first, last) < header.dims[0].length)
+ throw std::out_of_range("length of array out of range");
+
+ Iterator it = first;
+ for (int32_t i = 0; i != header.dims[0].length; i++, it++)
+ {
+ int32_t size;
+ data = detail::pop(data, size);
+ if (end - data < size)
+ throw std::overflow_error("insufficient data left in message");
+ data = object_traits<typename std::iterator_traits<Iterator>::value_type>::get(*it, data, data + size);
+ if (data >= end)
+ throw std::overflow_error("insufficient data left in message");
+ }
+ return data;
+ }
+ static std::pair<const char *, size_t> data(Iterator first, Iterator last, std::vector<char> &buffer)
+ {
+ assert(std::distance(first, last) <= INT32_MAX);
+ size_t n = buffer.size();
+ buffer.resize(n + sizeof(array_header));
+ array_header *header = reinterpret_cast<array_header *>(buffer.data() + n);
+ header->ndim = detail::hton(1);
+ header->flags = detail::hton(0);
+ header->elemtype = detail::hton(static_cast<int32_t>(object_traits<typename std::iterator_traits<Iterator>::value_type>::type_id));
+ header->dims[0].length = detail::hton(static_cast<int32_t>(std::distance(first, last)));
+ header->dims[0].lower_bound = detail::hton(1);
+
+ std::vector<char> temp;
+ for (Iterator it = first; it != last; it++)
+ {
+ std::pair<const char *, size_t> blob = object_traits<typename std::iterator_traits<Iterator>::value_type>::data(*it, temp);
+ detail::push(buffer, static_cast<int32_t>(blob.second));
+ buffer.insert(buffer.end(), blob.first, blob.first + blob.second);
+ }
+ return std::make_pair(buffer.data() + n, buffer.size() - n);
+ }
+ };
+
+ template <typename Iterator, Oid id>
+ struct range_traits : public base_object_traits<std::pair<Iterator, Iterator>, id>
+ {
+ static const char *get(std::pair<Iterator, Iterator> &result, const char *data, const char *end)
+ {
+ return iterator_traits<Iterator, id>::get(result.first, result.second, data, end);
+ }
+ static std::pair<const char *, size_t> data(const std::pair<Iterator, Iterator> &v, std::vector<char> &buffer)
+ {
+ return iterator_traits<Iterator, id>::data(v.first, v.second, buffer);
+ }
+ };
+
+ template <typename T>
+ struct object_traits<std::vector<T>> : public vector_traits<T, object_traits<T>::array_type_id>
+ {
+ };
+
+ template <typename Iterator>
+ struct object_traits<std::pair<typename std::enable_if<std::is_object<typename std::iterator_traits<Iterator>::value_type>::value, Iterator>::type, Iterator>> : public range_traits<Iterator, object_traits<typename std::iterator_traits<Iterator>::value_type>::array_type_id>
+ {
+ };
+
+ template <typename T, size_t N, Oid id>
+ struct carray_traits : public base_object_traits<T (&)[N], id>
+ {
+ static const char *get(T (&result)[N], const char *data, const char *end)
+ {
+ return iterator_traits<T *, id>::get(std::begin(result), std::end(result), data, end);
+ }
+ static std::pair<const char *, size_t> data(const T (&v)[N], std::vector<char> &buffer)
+ {
+ return iterator_traits<const T *, id>::data(std::begin(v), std::end(v), buffer);
+ }
+ };
+
+ template <typename T, size_t N, Oid id>
+ struct array_traits : public base_object_traits<std::array<T, N>, id>
+ {
+ static const char *get(std::array<T, N> &result, const char *data, const char *end)
+ {
+ return iterator_traits<T *, id>::get(std::begin(result), std::end(result), data, end);
+ }
+ static std::pair<const char *, size_t> data(const std::array<T, N> &v, std::vector<char> &buffer)
+ {
+ return iterator_traits<T *, id>::data(std::begin(v), std::end(v), buffer);
+ }
+ };
+
+ template <typename T, size_t N>
+ struct object_traits<T (&)[N]> : public carray_traits<T, N, object_traits<T>::array_type_id>
+ {
+ };
+
+ template <typename T, size_t N>
+ struct object_traits<std::array<T, N>> : public array_traits<T, N, object_traits<T>::array_type_id>
+ {
+ };
+
+ namespace detail
+ {
+
+ struct field_header
+ {
+ Oid type;
+ int32_t length;
+ };
+
+ template <typename Type>
+ static const char *get_field(Type &field, const char *data, const char *end)
+ {
+ field_header header = *reinterpret_cast<const field_header *>(data);
+ detail::ntoh_inplace(header.type);
+ detail::ntoh_inplace(header.length);
+ data += sizeof(field_header);
+ if (end - data < header.length)
+ throw std::overflow_error("insufficient data left in message");
+
+ return object_traits<Type>::get(field, data, data + header.length);
+ }
+
+ template <typename Tuple, size_t N>
+ struct get_field_helper
+ {
+ const char *operator()(Tuple &result, const char *data, const char *end)
+ {
+ if (end - data < sizeof(field_header))
+ throw std::overflow_error("insufficient data left in message");
+
+ auto &field = std::get<std::tuple_size<Tuple>::value - N>(result);
+ data = get_field(field, data, end);
+ get_field_helper<Tuple, N - 1>()(result, data, end);
+ return data;
+ }
+ };
+ template <typename Tuple>
+ struct get_field_helper<Tuple, 1>
+ {
+ const char *operator()(Tuple &result, const char *data, const char *end)
+ {
+ if (end - data < sizeof(field_header))
+ throw std::overflow_error("insufficient data left in message");
+
+ auto &field = std::get<std::tuple_size<Tuple>::value - 1>(result);
+ return get_field(field, data, end);
+ }
+ };
+
+ template <typename Type>
+ static void push_field(const Type &field, std::vector<char> &buffer)
+ {
+ std::vector<char> temp;
+ detail::push(buffer, static_cast<int32_t>(object_traits<Type>::type_id));
+ auto result = object_traits<Type>::data(field, temp);
+ detail::push(buffer, static_cast<int32_t>(result.second));
+ buffer.insert(buffer.end(), result.first, result.first + result.second);
+ }
+
+ template <typename Tuple, size_t N>
+ struct push_field_helper
+ {
+ void operator()(const Tuple &data, std::vector<char> &buffer)
+ {
+ const auto &field = std::get<std::tuple_size<Tuple>::value - N>(data);
+ push_field(field, buffer);
+ push_field_helper<Tuple, N - 1>()(data, buffer);
+ }
+ };
+ template <typename Tuple>
+ struct push_field_helper<Tuple, 1>
+ {
+ void operator()(const Tuple &data, std::vector<char> &buffer)
+ {
+ const auto &field = std::get<std::tuple_size<Tuple>::value - 1>(data);
+ push_field(field, buffer);
+ }
+ };
+
+ template <typename Tuple>
+ static const char *get_fields(Tuple &result, const char *data, const char *end)
+ {
+ return get_field_helper<Tuple, std::tuple_size<Tuple>::value>()(result, data, end);
+ }
+
+ template <typename Tuple>
+ static void push_fields(const Tuple &data, std::vector<char> &buffer)
+ {
+ push_field_helper<Tuple, std::tuple_size<Tuple>::value>()(data, buffer);
+ }
+
+ }
+
+ template <typename Tuple, Oid id>
+ struct tuple_traits : public base_object_traits<Tuple, id>
+ {
+ typedef typename base_object_traits<Tuple, id>::value_type value_type;
+ static const char *get(value_type &result, const char *data, const char *end)
+ {
+ int32_t count;
+ data = detail::pop(data, count);
+ if (data >= end)
+ throw std::overflow_error("insufficient data left in message");
+ if (std::tuple_size<Tuple>::value != count)
+ throw std::bad_cast();
+ return detail::get_fields(result, data, end);
+ }
+ static std::pair<const char *, size_t> data(const value_type &v, std::vector<char> &buffer)
+ {
+ size_t n = buffer.size();
+ detail::push(buffer, static_cast<int32_t>(std::tuple_size<value_type>::value));
+ detail::push_fields(v, buffer);
+ return std::make_pair(buffer.data() + n, buffer.size() - n);
+ }
+ };
+
+ template <typename... Types>
+ struct object_traits<std::tuple<Types...>> : public tuple_traits<std::tuple<Types...>, InvalidOid>
+ {
+ };
+
+ template <typename T1, typename T2>
+ struct object_traits<std::pair<T1, T2>> : public tuple_traits<std::pair<T1, T2>, InvalidOid>
+ {
+ };
+
+ struct binder
+ {
+ binder() = default;
+ template <typename T>
+ explicit binder(const T &v)
+ {
+ m_type = object_traits<T>::value();
+ auto pair = object_traits<T>::data(v);
+ m_value = pair.first;
+ m_length = pair.second;
+ }
+ binder(const char *data, size_t n, Oid oid)
+ {
+ m_type = oid;
+ m_value = data;
+ m_length = n;
+ }
+
+ Oid constexpr type() const { return m_type; }
+ size_t length() const { return m_length; }
+ const char *value() const { return m_value; }
+
+ template <typename T>
+ T get()
+ {
+ if (!object_traits<T>::is_match(m_type))
+ throw std::bad_cast();
+
+ T v;
+ object_traits<T>::get(v, m_value, m_value + m_length);
+ return v;
+ }
+ template <typename T>
+ T get(PGconn *conn)
+ {
+ if (!object_traits<T>::is_match(m_type))
+ throw std::bad_cast();
+
+ return object_traits<T>::get(conn, m_value, m_value + m_length);
+ }
+ template <typename T>
+ void get(T &v)
+ {
+ if (object_traits<T>::type_id != InvalidOid && !object_traits<T>::is_match(m_type))
+ throw std::bad_cast();
+
+ object_traits<T>::get(v, m_value, m_value + m_length);
+ }
+
+ void bind(std::nullptr_t)
+ {
+ m_value = nullptr;
+ m_length = 0;
+ }
+ void bind(qtl::null)
+ {
+ bind(nullptr);
+ }
+
+ template <typename T, typename = typename std::enable_if<!std::is_array<T>::value>::type>
+ void bind(const T &v)
+ {
+ typedef typename std::decay<T>::type param_type;
+ if (m_type != 0 && !object_traits<param_type>::is_match(m_type))
+ throw std::bad_cast();
+
+ auto pair = object_traits<param_type>::data(v, m_data);
+ m_value = pair.first;
+ m_length = pair.second;
+ }
+ void bind(const char *data, size_t length = 0)
+ {
+ m_value = data;
+ if (length > 0)
+ m_length = length;
+ else
+ m_length = strlen(data);
+ }
+ template <typename T, size_t N>
+ void bind(const T (&v)[N])
+ {
+ if (m_type != 0 && !object_traits<T(&)[N]>::is_match(m_type))
+ throw std::bad_cast();
+
+ auto pair = object_traits<T(&)[N]>::data(v, m_data);
+ m_value = pair.first;
+ m_length = pair.second;
+ }
+
+ private:
+ Oid m_type;
+ const char *m_value;
+ size_t m_length;
+ std::vector<char> m_data;
+ };
+
+ template <size_t N, size_t I, typename Arg, typename... Other>
+ inline void make_binder_list_helper(std::array<binder, N> &binders, Arg &&arg, Other &&...other)
+ {
+ binders[I] = binder(arg);
+ make_binder_list_helper<N, I + 1>(binders, std::forward<Other>(other)...);
+ }
+
+ template <typename... Args>
+ inline std::array<binder, sizeof...(Args)> make_binder_list(Args &&...args)
+ {
+ std::array<binder, sizeof...(Args)> binders;
+ binders.reserve(sizeof...(Args));
+ make_binder_list_helper<sizeof...(Args), 0>(binders, std::forward<Args>(args)...);
+ return binders;
+ }
+
+ template <typename T>
+ inline bool in_impl(const T &from, const T &to)
+ {
+ return std::equal_to<T>()(from, to);
+ }
+
+ template <typename T, typename... Ts>
+ inline bool in_impl(const T &from, const T &to, const Ts &...other)
+ {
+ return std::equal_to<T>()(from, to) || in_impl(from, other...);
+ }
+
+ template <typename T, T... values>
+ inline bool in(const T &v)
+ {
+ return in_impl(v, values...);
+ }
+
+ class result
+ {
+ public:
+ result(PGresult *res) : m_res(res) {}
+ result(const result &) = delete;
+ result(result &&src)
+ {
+ m_res = src.m_res;
+ src.m_res = nullptr;
+ }
+
+ result &operator=(const result &) = delete;
+ result &operator=(result &&src)
+ {
+ if (this != &src)
+ {
+ clear();
+ m_res = src.m_res;
+ src.m_res = nullptr;
+ }
+ return *this;
+ }
+ ~result()
+ {
+ clear();
+ }
+
+ PGresult *handle() const { return m_res; }
+ operator bool() const { return m_res != nullptr; }
+
+ ExecStatusType status() const
+ {
+ return PQresultStatus(m_res);
+ }
+
+ long long affected_rows() const
+ {
+ char *result = PQcmdTuples(m_res);
+ if (result)
+ return strtoll(result, nullptr, 10);
+ else
+ return 0LL;
+ }
+
+ unsigned int get_column_count() const { return PQnfields(m_res); }
+
+ int get_param_count() const
+ {
+ return PQnparams(m_res);
+ }
+
+ Oid get_param_type(int col) const
+ {
+ return PQparamtype(m_res, col);
+ }
+
+ const char *get_column_name(int col) const
+ {
+ return PQfname(m_res, col);
+ }
+ int get_column_index(const char *name) const
+ {
+ return PQfnumber(m_res, name);
+ }
+ int get_column_length(int col) const
+ {
+ return PQfsize(m_res, col);
+ }
+ Oid get_column_type(int col) const
+ {
+ return PQftype(m_res, col);
+ }
+
+ const char *get_value(int row, int col) const
+ {
+ return PQgetvalue(m_res, row, col);
+ }
+
+ bool is_null(int row, int col) const
+ {
+ return PQgetisnull(m_res, row, col);
+ }
+
+ int length(int row, int col) const
+ {
+ return PQgetlength(m_res, row, col);
+ }
+
+ Oid insert_oid() const
+ {
+ return PQoidValue(m_res);
+ }
+
+ template <ExecStatusType... Excepted>
+ void verify_error()
+ {
+ if (m_res)
+ {
+ ExecStatusType got = status();
+ if (!in<ExecStatusType, Excepted...>(got))
+ throw error(m_res);
+ }
+ }
+
+ template <ExecStatusType... Excepted>
+ void verify_error(error &e)
+ {
+ if (m_res)
+ {
+ ExecStatusType got = status();
+ if (!in<ExecStatusType, Excepted...>(got))
+ e = error(m_res);
+ }
+ }
+
+ void clear()
+ {
+ if (m_res)
+ {
+ PQclear(m_res);
+ m_res = nullptr;
+ }
+ }
+
+ private:
+ PGresult *m_res;
+ };
+
+ class base_statement
+ {
+ friend class error;
+
+ public:
+ explicit base_statement(base_database &db);
+ ~base_statement()
+ {
+ }
+ base_statement(const base_statement &) = delete;
+ base_statement(base_statement &&src)
+ : m_conn(src.m_conn), m_binders(std::move(src.m_binders)), m_res(std::move(src.m_res)), _name(std::move(src._name))
+ {
+ }
+ base_statement &operator=(const base_statement &) = delete;
+ base_statement &operator=(base_statement &&src)
+ {
+ if (this != &src)
+ {
+ close();
+ m_conn = src.m_conn;
+ m_binders = std::move(src.m_binders);
+ m_res = std::move(src.m_res);
+ }
+ return *this;
+ }
+
+ result &get_result() { return m_res; }
+
+ void close()
+ {
+ m_res = nullptr;
+ }
+
+ uint64_t affetced_rows() const
+ {
+ return m_res.affected_rows();
+ }
+
+ void bind_param(size_t index, const char *param, size_t length)
+ {
+ m_binders[index].bind(param, length);
+ }
+ template <class Param>
+ void bind_param(size_t index, const Param ¶m)
+ {
+ m_binders[index].bind(param);
+ }
+
+ template <class Type>
+ void bind_field(size_t index, Type &&value)
+ {
+ if (m_res.is_null(0, static_cast<int>(index)))
+ value = Type();
+ else
+ value = m_binders[index].get<typename std::remove_const<Type>::type>();
+ }
+
+ void bind_field(size_t index, char *value, size_t length)
+ {
+ memcpy(value, m_binders[index].value(), std::min<size_t>(length, m_binders[index].length()));
+ }
+
+ template <size_t N>
+ void bind_field(size_t index, std::array<char, N> &&value)
+ {
+ bind_field(index, value.data(), value.size());
+ }
+
+ template <typename T>
+ void bind_field(size_t index, bind_string_helper<T> &&value)
+ {
+ value.assign(m_binders[index].value(), m_binders[index].length());
+ }
+
+ template <typename Type>
+ void bind_field(size_t index, indicator<Type> &&value)
+ {
+ if (m_res)
+ {
+ qtl::bind_field(*this, index, value.data);
+ value.is_null = m_res.is_null(0, static_cast<int>(index));
+ value.length = m_res.length(0, static_cast<int>(index));
+ value.is_truncated = m_binders[index].length() < value.length;
+ }
+ }
+
+ void bind_field(size_t index, large_object &&value)
+ {
+ if (m_res.is_null(0, static_cast<int>(index)))
+ value.close();
+ else
+ value = m_binders[index].get<large_object>(m_conn);
+ }
+ void bind_field(size_t index, blob_data &&value)
+ {
+ if (m_res.is_null(0, static_cast<int>(index)))
+ {
+ value.data = nullptr;
+ value.size = 0;
}
else
{
- handler(postgres::error(conn));
+ m_binders[index].get(value);
}
+ }
+
+ template <typename... Types>
+ void bind_field(size_t index, std::tuple<Types...> &&value)
+ {
+ if (m_res.is_null(0, static_cast<int>(index)))
+ value = std::tuple<Types...>();
+ else
+ m_binders[index].get(value);
+ }
+
+#ifdef _QTL_ENABLE_CPP17
+
+ template <typename T>
+ inline void bind_field(size_t index, std::optional<T> &&value)
+ {
+ if (m_res.is_null(0, static_cast<int>(index)))
+ {
+ value.reset();
+ }
+ else
+ {
+ T v;
+ bind_field(index, v);
+ value = std::move(v);
+ }
+ }
+
+ void bind_field(size_t index, std::any &&value)
+ {
+ if (m_res.is_null(0, static_cast<int>(index)))
+ {
+ value = nullptr;
+ }
+ else
+ {
+ Oid oid = m_res.get_column_type(index);
+ switch (oid)
+ {
+ case object_traits<bool>::type_id:
+ value = field_cast<bool>(index);
+ break;
+ case object_traits<char>::type_id:
+ value = field_cast<char>(index);
+ break;
+ case object_traits<float>::type_id:
+ value = field_cast<float>(index);
+ break;
+ case object_traits<double>::type_id:
+ value = field_cast<double>(index);
+ break;
+ case object_traits<int16_t>::type_id:
+ value = field_cast<int16_t>(index);
+ break;
+ case object_traits<int32_t>::type_id:
+ value = field_cast<int32_t>(index);
+ break;
+ case object_traits<int64_t>::type_id:
+ value = field_cast<int64_t>(index);
+ break;
+ case object_traits<Oid>::type_id:
+ value = field_cast<Oid>(index);
+ break;
+ case object_traits<std::string>::type_id:
+ value = field_cast<std::string>(index);
+ break;
+ case object_traits<timestamp>::type_id:
+ value = field_cast<timestamp>(index);
+ break;
+ case object_traits<interval>::type_id:
+ value = field_cast<interval>(index);
+ break;
+ case object_traits<date>::type_id:
+ value = field_cast<date>(index);
+ break;
+ case object_traits<std::vector<uint8_t>>::type_id:
+ value = field_cast<std::vector<uint8_t>>(index);
+ break;
+ case object_traits<bool>::array_type_id:
+ value = field_cast<std::vector<bool>>(index);
+ break;
+ case object_traits<char>::array_type_id:
+ value = field_cast<std::vector<char>>(index);
+ break;
+ case object_traits<float>::array_type_id:
+ value = field_cast<std::vector<float>>(index);
+ break;
+ case object_traits<double>::array_type_id:
+ value = field_cast<std::vector<double>>(index);
+ break;
+ case object_traits<int16_t>::array_type_id:
+ value = field_cast<std::vector<int16_t>>(index);
+ break;
+ case object_traits<int32_t>::array_type_id:
+ value = field_cast<std::vector<int32_t>>(index);
+ break;
+ case object_traits<int64_t>::array_type_id:
+ value = field_cast<std::vector<int64_t>>(index);
+ break;
+ case object_traits<Oid>::array_type_id:
+ value = field_cast<std::vector<Oid>>(index);
+ break;
+ case object_traits<std::string>::array_type_id:
+ value = field_cast<std::vector<std::string>>(index);
+ break;
+ case object_traits<timestamp>::array_type_id:
+ value = field_cast<std::vector<timestamp>>(index);
+ break;
+ case object_traits<interval>::array_type_id:
+ value = field_cast<std::vector<interval>>(index);
+ break;
+ case object_traits<date>::array_type_id:
+ value = field_cast<std::vector<date>>(index);
+ break;
+ default:
+ throw postgres::error("Unsupported field type");
+ }
+ }
+ }
+
+#endif // C++17
+
+ protected:
+ PGconn *m_conn;
+ result m_res;
+ std::string _name;
+ std::vector<binder> m_binders;
+
+ template <ExecStatusType... Excepted>
+ void verify_error()
+ {
+ if (m_res)
+ m_res.verify_error<Excepted...>();
+ else
+ throw error(m_conn);
+ }
+ void finish(result &res)
+ {
+ while (res)
+ {
+ res = PQgetResult(m_conn);
+ }
+ }
+
+ template <typename T>
+ T field_cast(size_t index)
+ {
+ T v;
+ m_binders[index].get(v);
+ return v;
+ }
+ };
+
+ class statement : public base_statement
+ {
+ public:
+ explicit statement(base_database &db) : base_statement(db)
+ {
+ }
+ statement(const statement &) = delete;
+ statement(statement &&src) : base_statement(std::move(src))
+ {
+ }
+
+ ~statement()
+ {
+ finish(m_res);
+
+ if (!_name.empty())
+ {
+ std::ostringstream oss;
+ oss << "DEALLOCATE " << _name << ";";
+ result res = PQexec(m_conn, oss.str().data());
+ error e(res.handle());
+ }
+ }
+
+ void open(const char *command, int nParams = 0, const Oid *paramTypes = nullptr)
+ {
+ _name.resize(sizeof(intptr_t) * 2 + 1);
+ int n = sprintf(const_cast<char *>(_name.data()), "q%p", this);
+ _name.resize(n);
+ std::transform(_name.begin(), _name.end(), _name.begin(), tolower);
+ result res = PQprepare(m_conn, _name.data(), command, nParams, paramTypes);
+ res.verify_error<PGRES_COMMAND_OK>();
+ }
+ template <typename... Types>
+ void open(const char *command)
+ {
+ auto binder_list = make_binder_list(Types()...);
+ std::array<Oid, sizeof...(Types)> types;
+ std::transform(binder_list.begin(), binder_list.end(), types.begin(), [](const binder &b)
+ { return b.type(); });
+
+ open(command, types.size(), types.data());
+ }
+
+ void attach(const char *name)
+ {
+ result res = PQdescribePrepared(m_conn, name);
+ res.verify_error<PGRES_COMMAND_OK>();
+ _name = name;
+ }
+
+ void execute()
+ {
+ if (!PQsendQueryPrepared(m_conn, _name.data(), 0, nullptr, nullptr, nullptr, 1))
+ throw error(m_conn);
+ if (!PQsetSingleRowMode(m_conn))
+ throw error(m_conn);
+ m_res = PQgetResult(m_conn);
+ verify_error<PGRES_COMMAND_OK, PGRES_SINGLE_TUPLE>();
+ }
+
+ template <typename Types>
+ void execute(const Types ¶ms)
+ {
+ const size_t count = qtl::params_binder<statement, Types>::size;
+ if (count > 0)
+ {
+ m_binders.resize(count);
+ qtl::bind_params(*this, params);
+
+ std::array<const char *, count> values;
+ std::array<int, count> lengths;
+ std::array<int, count> formats;
+ for (size_t i = 0; i != m_binders.size(); i++)
+ {
+ values[i] = m_binders[i].value();
+ lengths[i] = static_cast<int>(m_binders[i].length());
+ formats[i] = 1;
+ }
+ if (!PQsendQueryPrepared(m_conn, _name.data(), static_cast<int>(m_binders.size()), values.data(), lengths.data(), formats.data(), 1))
+ throw error(m_conn);
+ }
+ else
+ {
+ if (!PQsendQueryPrepared(m_conn, _name.data(), 0, nullptr, nullptr, nullptr, 1))
+ throw error(m_conn);
+ }
+ if (!PQsetSingleRowMode(m_conn))
+ throw error(m_conn);
+ m_res = PQgetResult(m_conn);
+ verify_error<PGRES_COMMAND_OK, PGRES_SINGLE_TUPLE, PGRES_TUPLES_OK>();
+ }
+
+ template <typename Types>
+ bool fetch(Types &&values)
+ {
+ if (m_res)
+ {
+ ExecStatusType status = m_res.status();
+ if (status == PGRES_SINGLE_TUPLE)
+ {
+ int count = m_res.get_column_count();
+ if (count > 0)
+ {
+ m_binders.resize(count);
+ for (int i = 0; i != count; i++)
+ {
+ m_binders[i] = binder(m_res.get_value(0, i), m_res.length(0, i),
+ m_res.get_column_type(i));
+ }
+ qtl::bind_record(*this, std::forward<Types>(values));
+ }
+ m_res = PQgetResult(m_conn);
+ return true;
+ }
+ else
+ {
+ verify_error<PGRES_TUPLES_OK>();
+ }
+ }
+ return false;
+ }
+
+ bool next_result()
+ {
+ m_res = PQgetResult(m_conn);
+ return m_res && m_res.status() == PGRES_SINGLE_TUPLE;
+ }
+
+ void reset()
+ {
+ finish(m_res);
+ m_res.clear();
+ }
+ };
+
+ class base_database
+ {
+ protected:
+ base_database()
+ {
+ m_conn = nullptr;
+ }
+
+ public:
+ typedef postgres::error exception_type;
+
+ base_database(const base_database &) = delete;
+ base_database(base_database &&src)
+ {
+ m_conn = src.m_conn;
+ src.m_conn = nullptr;
+ }
+
+ ~base_database()
+ {
+ if (m_conn)
+ PQfinish(m_conn);
+ }
+
+ base_database &operator=(const base_database &) = delete;
+ base_database &operator=(base_database &&src)
+ {
+ if (this != &src)
+ {
+ if (m_conn)
+ PQfinish(m_conn);
+ m_conn = src.m_conn;
+ src.m_conn = nullptr;
+ }
+ return *this;
+ }
+
+ const char *errmsg() const
+ {
+ return PQerrorMessage(m_conn);
+ }
+
+ PGconn *handle() { return m_conn; }
+
+ const char *encoding() const
+ {
+ int encoding = PQclientEncoding(m_conn);
+ return (encoding >= 0) ? pg_encoding_to_char(encoding) : nullptr;
+ }
+
+ void encoding(const char *encoding)
+ {
+ if (PQsetClientEncoding(m_conn, encoding))
+ throw error(m_conn);
+ }
+
+ void trace(FILE *stream)
+ {
+ PQtrace(m_conn, stream);
+ }
+ void untrace()
+ {
+ PQuntrace(m_conn);
+ }
+
+ const char *current() const
+ {
+ return PQdb(m_conn);
+ }
+
+ const char *user() const
+ {
+ return PQuser(m_conn);
+ }
+
+ const char *host() const
+ {
+ return PQhost(m_conn);
+ }
+
+ const char *password() const
+ {
+ return PQpass(m_conn);
+ }
+
+ const char *port() const
+ {
+ return PQport(m_conn);
+ }
+
+ const char *options() const
+ {
+ return PQoptions(m_conn);
+ }
+
+ ConnStatusType status() const
+ {
+ return PQstatus(m_conn);
+ }
+
+ PGTransactionStatusType transactionStatus() const
+ {
+ return PQtransactionStatus(m_conn);
+ }
+
+ const char *parameterStatus(const char *paramName) const
+ {
+ return PQparameterStatus(m_conn, paramName);
+ }
+
+ void reset()
+ {
+ if (status() == CONNECTION_BAD)
+ PQreset(m_conn);
+ }
+
+ void close()
+ {
+ PQfinish(m_conn);
+ m_conn = nullptr;
+ }
+
+ protected:
+ PGconn *m_conn;
+ void throw_exception() { throw postgres::error(m_conn); }
+ };
+
+ class simple_statment : public base_statement
+ {
+ public:
+ simple_statment(base_database &db, qtl::postgres::result &&res) : base_statement(db)
+ {
+ m_res = std::move(res);
+ }
+
+ template <typename ValueProc>
+ void fetch_all(ValueProc &proc)
+ {
+ int row_count = PQntuples(m_res.handle());
+ if (row_count > 0)
+ {
+ int col_count = m_res.get_column_count();
+ m_binders.resize(col_count);
+ auto values = qtl::detail::make_values(proc);
+ for (int i = 0; i != row_count; i++)
+ {
+ for (int j = 0; j != col_count; j++)
+ {
+ m_binders[j] = binder(m_res.get_value(i, j), m_res.length(i, j),
+ m_res.get_column_type(j));
+ }
+ qtl::bind_record(*this, std::forward<decltype(values)>(values));
+ qtl::detail::apply(proc, std::forward<decltype(values)>(values));
+ }
+ }
+ }
+ };
+
+ class database : public base_database, public qtl::base_database<database, statement>
+ {
+ public:
+ database() = default;
+
+ bool open(const std::map<std::string, std::string> ¶ms, bool expand_dbname = false)
+ {
+ std::vector<const char *> keywords(params.size() + 1);
+ std::vector<const char *> values(params.size() + 1);
+ for (auto ¶m : params)
+ {
+ keywords.push_back(param.first.data());
+ values.push_back(param.second.data());
+ }
+ keywords.push_back(nullptr);
+ values.push_back(nullptr);
+ m_conn = PQconnectdbParams(keywords.data(), values.data(), expand_dbname);
+ return m_conn != nullptr && status() == CONNECTION_OK;
+ }
+
+ bool open(const char *conninfo)
+ {
+ m_conn = PQconnectdb(conninfo);
+ return m_conn != nullptr && status() == CONNECTION_OK;
+ }
+
+ bool open(const char *host, const char *user, const char *password,
+ unsigned short port = 5432, const char *db = "postgres", const char *options = nullptr)
+ {
+ char port_text[16];
+ sprintf(port_text, "%u", port);
+ m_conn = PQsetdbLogin(host, port_text, options, nullptr, db, user, password);
+ return m_conn != nullptr && status() == CONNECTION_OK;
+ }
+
+ statement open_command(const char *query_text, size_t /*text_length*/)
+ {
+ statement stmt(*this);
+ stmt.open(query_text);
+ return stmt;
+ }
+ statement open_command(const char *query_text)
+ {
+ return open_command(query_text, 0);
+ }
+ statement open_command(const std::string &query_text)
+ {
+ return open_command(query_text.data());
+ }
+
+ void simple_execute(const char *query_text, uint64_t *paffected = nullptr)
+ {
+ qtl::postgres::result res(PQexec(m_conn, query_text));
+ if (!res)
+ throw_exception();
+ res.verify_error<PGRES_COMMAND_OK, PGRES_TUPLES_OK>();
+ if (paffected)
+ *paffected = res.affected_rows();
+ }
+ template <typename ValueProc>
+ void simple_query(const char *query_text, ValueProc &&proc)
+ {
+ qtl::postgres::result res(PQexec(m_conn, query_text));
+ if (!res)
+ throw_exception();
+ res.verify_error<PGRES_COMMAND_OK, PGRES_TUPLES_OK>();
+ if (res.status() == PGRES_TUPLES_OK)
+ {
+ simple_statment stmt(*this, std::move(res));
+ stmt.fetch_all(std::forward<ValueProc>(proc));
+ }
+ }
+
+ void auto_commit(bool on)
+ {
+ if (on)
+ simple_execute("SET AUTOCOMMIT TO ON");
+ else
+ simple_execute("SET AUTOCOMMIT TO OFF");
+ }
+
+ void begin_transaction()
+ {
+ simple_execute("BEGIN");
+ }
+ void rollback()
+ {
+ simple_execute("ROLLBACK");
+ }
+ void commit()
+ {
+ simple_execute("COMMIT");
+ }
+
+ bool is_alive()
+ {
+ qtl::postgres::result res(PQexec(m_conn, ""));
+ return res && res.status() == PGRES_COMMAND_OK;
+ }
+ };
+
+ inline int event_flags(PostgresPollingStatusType status)
+ {
+ int flags = 0;
+ if (status == PGRES_POLLING_READING)
+ flags |= event::ef_read;
+ else if (status == PGRES_POLLING_WRITING)
+ flags |= event::ef_write;
+ else if (status == PGRES_POLLING_FAILED)
+ flags |= event::ef_exception;
+ return flags;
+ }
+
+ class async_connection;
+
+ template <typename Handler>
+ inline void async_wait(qtl::event *event, PGconn *conn, int timeout, Handler &&handler)
+ {
+ int flushed = PQflush(conn);
+ if (flushed < 0)
+ {
+ handler(error(conn));
+ return;
+ }
+ if (flushed == 1)
+ {
+ event->set_io_handler(qtl::event::ef_read | qtl::event::ef_write, timeout,
+ [event, conn, timeout, handler](int flags) mutable
+ {
+ if (flags & qtl::event::ef_timeout)
+ {
+ handler(postgres::timeout());
+ return;
+ }
+ if (flags & qtl::event::ef_read)
+ {
+ if (!PQconsumeInput(conn))
+ {
+ handler(error(conn));
+ return;
+ }
+ }
+ if (flags & (qtl::event::ef_read | qtl::event::ef_write | event::ef_exception))
+ async_wait(event, conn, timeout, handler);
+ });
}
else
{
- handler(postgres::error(conn));
+ event->set_io_handler(qtl::event::ef_read, 10,
+ [event, conn, timeout, handler](int flags) mutable
+ {
+ if (flags & qtl::event::ef_timeout)
+ {
+ handler(postgres::timeout());
+ }
+ else if (flags & (qtl::event::ef_read | qtl::event::ef_exception))
+ {
+ if (PQconsumeInput(conn))
+ {
+ if (!PQisBusy(conn))
+ handler(postgres::error());
+ else
+ async_wait(event, conn, timeout, handler);
+ }
+ else
+ {
+ handler(postgres::error(conn));
+ }
+ }
+ else
+ {
+ handler(postgres::error(conn));
+ }
+ });
}
- });
- }
-}
-
-class async_statement : public base_statement
-{
-public:
- async_statement(async_connection& db);
- async_statement(async_statement&& src)
- : base_statement(std::move(src)), m_timeout(2)
- {
- m_event = src.m_event;
- m_timeout = src.m_timeout;
- src.m_event = nullptr;
- }
- async_statement& operator=(async_statement&& src)
- {
- if (this != &src)
- {
- base_statement::operator =(std::move(src));
- m_event = src.m_event;
- m_timeout = src.m_timeout;
- src.m_event = nullptr;
}
- return *this;
- }
- ~async_statement()
- {
- close();
- }
- /*
- Handler defiens as:
- void handler(const qtl::mysql::error& e);
- */
- template<typename Handler>
- void open(Handler&& handler, const char* command, int nParams = 0, const Oid *paramTypes = nullptr)
- {
- _name.resize(sizeof(intptr_t) * 2 + 1);
- int n = sprintf(const_cast<char*>(_name.data()), "q%p", this);
- _name.resize(n);
- std::transform(_name.begin(), _name.end(), _name.begin(), tolower);
- if (PQsendPrepare(m_conn, _name.data(), command, nParams, paramTypes))
+ class async_statement : public base_statement
{
- async_wait([this, handler](error e) mutable {
+ public:
+ async_statement(async_connection &db);
+ async_statement(async_statement &&src)
+ : base_statement(std::move(src)), m_timeout(2)
+ {
+ m_event = src.m_event;
+ m_timeout = src.m_timeout;
+ src.m_event = nullptr;
+ }
+ async_statement &operator=(async_statement &&src)
+ {
+ if (this != &src)
+ {
+ base_statement::operator=(std::move(src));
+ m_event = src.m_event;
+ m_timeout = src.m_timeout;
+ src.m_event = nullptr;
+ }
+ return *this;
+ }
+ ~async_statement()
+ {
+ close();
+ }
+
+ /*
+ Handler defiens as:
+ void handler(const qtl::mysql::error& e);
+ */
+ template <typename Handler>
+ void open(Handler &&handler, const char *command, int nParams = 0, const Oid *paramTypes = nullptr)
+ {
+ _name.resize(sizeof(intptr_t) * 2 + 1);
+ int n = sprintf(const_cast<char *>(_name.data()), "q%p", this);
+ _name.resize(n);
+ std::transform(_name.begin(), _name.end(), _name.begin(), tolower);
+ if (PQsendPrepare(m_conn, _name.data(), command, nParams, paramTypes))
+ {
+ async_wait([this, handler](error e) mutable
+ {
if (!e)
{
m_res = PQgetResult(m_conn);
@@ -2345,73 +2407,72 @@
m_res = PQgetResult(m_conn);
}
}
- handler(e);
- });
- }
- else
- {
- _name.clear();
- handler(error(m_conn));
- }
- }
-
- template<typename Handler, typename... Types>
- void open(Handler&& handler, const char* command)
- {
- auto binder_list = make_binder_list(Types()...);
- std::array<Oid, sizeof...(Types)> types;
- std::transform(binder_list.begin(), binder_list.end(), types.begin(), [](const binder& b) {
- return b.type();
- });
-
- open(std::forward<Handler>(handler), command, types.size(), types.data());
- }
-
- void close()
- {
- while (m_res)
- {
- m_res = PQgetResult(m_conn);
- }
-
- if (!_name.empty())
- {
- std::ostringstream oss;
- oss << "DEALLOCATE " << _name << ";";
- result res = PQexec(m_conn, oss.str().data());
- error e;
- res.verify_error<PGRES_COMMAND_OK, PGRES_TUPLES_OK>(e);
- finish(res);
- if(e) throw e;
- }
- base_statement::close();
- }
-
- template<typename Handler>
- void close(Handler&& handler)
- {
- while (m_res)
- {
- if(PQisBusy(m_conn))
- {
- async_wait([this, handler](const error& e) mutable {
- close(handler);
- });
+ handler(e); });
+ }
+ else
+ {
+ _name.clear();
+ handler(error(m_conn));
+ }
}
- else
- {
- m_res = PQgetResult(m_conn);
- }
- }
- if (!_name.empty() && PQstatus(m_conn) == CONNECTION_OK)
- {
- std::ostringstream oss;
- oss << "DEALLOCATE " << _name << ";";
- bool ok = PQsendQuery(m_conn, oss.str().data());
- if (ok)
+ template <typename Handler, typename... Types>
+ void open(Handler &&handler, const char *command)
{
- async_wait([this, handler](postgres::error e) mutable {
+ auto binder_list = make_binder_list(Types()...);
+ std::array<Oid, sizeof...(Types)> types;
+ std::transform(binder_list.begin(), binder_list.end(), types.begin(), [](const binder &b)
+ { return b.type(); });
+
+ open(std::forward<Handler>(handler), command, types.size(), types.data());
+ }
+
+ void close()
+ {
+ while (m_res)
+ {
+ m_res = PQgetResult(m_conn);
+ }
+
+ if (!_name.empty())
+ {
+ std::ostringstream oss;
+ oss << "DEALLOCATE " << _name << ";";
+ result res = PQexec(m_conn, oss.str().data());
+ error e;
+ res.verify_error<PGRES_COMMAND_OK, PGRES_TUPLES_OK>(e);
+ finish(res);
+ if (e)
+ throw e;
+ }
+ base_statement::close();
+ }
+
+ template <typename Handler>
+ void close(Handler &&handler)
+ {
+ while (m_res)
+ {
+ if (PQisBusy(m_conn))
+ {
+ async_wait([this, handler](const error &e) mutable
+ { close(handler); });
+ }
+ else
+ {
+ m_res = PQgetResult(m_conn);
+ }
+ }
+
+ if (!_name.empty() && PQstatus(m_conn) == CONNECTION_OK)
+ {
+ std::ostringstream oss;
+ oss << "DEALLOCATE " << _name << ";";
+ bool ok = PQsendQuery(m_conn, oss.str().data());
+ if (ok)
+ {
+ async_wait([this, handler](postgres::error e) mutable
+ {
if (PQstatus(m_conn) == CONNECTION_OK)
{
result res(PQgetResult(m_conn));
@@ -2425,86 +2486,86 @@
{
_name.clear();
handler(error());
+ } });
}
- });
+ else
+ {
+ handler(error(m_conn));
+ }
+ }
+ else
+ {
+ _name.clear();
+ }
}
- else
- {
- handler(error(m_conn));
- }
- }
- else
- {
- _name.clear();
- }
- }
- /*
- ExecuteHandler defiens as:
- void handler(const qtl::mysql::error& e, uint64_t affected);
- */
- template<typename ExecuteHandler>
- void execute(ExecuteHandler&& handler)
- {
- if (PQsendQueryPrepared(m_conn, _name.data(), 0, nullptr, nullptr, nullptr, 1) &&
- PQsetSingleRowMode(m_conn))
- {
- async_wait([this, handler](error e) {
+ /*
+ ExecuteHandler defiens as:
+ void handler(const qtl::mysql::error& e, uint64_t affected);
+ */
+ template <typename ExecuteHandler>
+ void execute(ExecuteHandler &&handler)
+ {
+ if (PQsendQueryPrepared(m_conn, _name.data(), 0, nullptr, nullptr, nullptr, 1) &&
+ PQsetSingleRowMode(m_conn))
+ {
+ async_wait([this, handler](error e)
+ {
if (!e)
{
m_res = PQgetResult(m_conn);
m_res.verify_error<PGRES_COMMAND_OK, PGRES_SINGLE_TUPLE>(e);
finish(m_res);
}
- handler(e);
- });
- }
- else
- {
- handler(error(m_conn));
- }
- }
+ handler(e); });
+ }
+ else
+ {
+ handler(error(m_conn));
+ }
+ }
- template<typename Types, typename Handler>
- void execute(const Types& params, Handler&& handler)
- {
- const size_t count = qtl::params_binder<statement, Types>::size;
- if (count > 0)
- {
- m_binders.resize(count);
- qtl::bind_params(*this, params);
+ template <typename Types, typename Handler>
+ void execute(const Types ¶ms, Handler &&handler)
+ {
+ const size_t count = qtl::params_binder<statement, Types>::size;
+ if (count > 0)
+ {
+ m_binders.resize(count);
+ qtl::bind_params(*this, params);
- std::array<const char*, count> values;
- std::array<int, count> lengths;
- std::array<int, count> formats;
- for (size_t i = 0; i != m_binders.size(); i++)
- {
- values[i] = m_binders[i].value();
- lengths[i] = static_cast<int>(m_binders[i].length());
- formats[i] = 1;
- }
- if (!PQsendQueryPrepared(m_conn, _name.data(), static_cast<int>(m_binders.size()), values.data(), lengths.data(), formats.data(), 1))
- {
- handler(error(m_conn), 0);
- return;
- }
- }
- else
- {
- if (!PQsendQueryPrepared(m_conn, _name.data(), 0, nullptr, nullptr, nullptr, 1))
- {
- handler(error(m_conn), 0);
- return;
- }
- }
- if (!PQsetSingleRowMode(m_conn))
- {
- handler(error(m_conn), 0);
- return;
- }
- if (PQisBusy(m_conn))
- {
- async_wait([this, handler](error e) mutable {
+ std::array<const char *, count> values;
+ std::array<int, count> lengths;
+ std::array<int, count> formats;
+ for (size_t i = 0; i != m_binders.size(); i++)
+ {
+ values[i] = m_binders[i].value();
+ lengths[i] = static_cast<int>(m_binders[i].length());
+ formats[i] = 1;
+ }
+ if (!PQsendQueryPrepared(m_conn, _name.data(), static_cast<int>(m_binders.size()), values.data(), lengths.data(), formats.data(), 1))
+ {
+ handler(error(m_conn), 0);
+ return;
+ }
+ }
+ else
+ {
+ if (!PQsendQueryPrepared(m_conn, _name.data(), 0, nullptr, nullptr, nullptr, 1))
+ {
+ handler(error(m_conn), 0);
+ return;
+ }
+ }
+ if (!PQsetSingleRowMode(m_conn))
+ {
+ handler(error(m_conn), 0);
+ return;
+ }
+ if (PQisBusy(m_conn))
+ {
+ async_wait([this, handler](error e) mutable
+ {
if (!e)
{
m_res = PQgetResult(m_conn);
@@ -2516,34 +2577,34 @@
else
{
handler(e, 0);
+ } });
}
- });
- }
- }
+ }
- template<typename Types, typename RowHandler, typename FinishHandler>
- void fetch(Types&& values, RowHandler&& row_handler, FinishHandler&& finish_handler)
- {
- if (m_res)
- {
- ExecStatusType status = m_res.status();
- if (status == PGRES_SINGLE_TUPLE)
+ template <typename Types, typename RowHandler, typename FinishHandler>
+ void fetch(Types &&values, RowHandler &&row_handler, FinishHandler &&finish_handler)
{
- int count = m_res.get_column_count();
- if (count > 0)
+ if (m_res)
{
- m_binders.resize(count);
- for (int i = 0; i != count; i++)
+ ExecStatusType status = m_res.status();
+ if (status == PGRES_SINGLE_TUPLE)
{
- m_binders[i] = binder(m_res.get_value(0, i), m_res.length(0, i),
- m_res.get_column_type(i));
- }
- qtl::bind_record(*this, std::forward<Types>(values));
- }
- row_handler();
- if (PQisBusy(m_conn))
- {
- async_wait([this, &values, row_handler, finish_handler](const error& e) {
+ int count = m_res.get_column_count();
+ if (count > 0)
+ {
+ m_binders.resize(count);
+ for (int i = 0; i != count; i++)
+ {
+ m_binders[i] = binder(m_res.get_value(0, i), m_res.length(0, i),
+ m_res.get_column_type(i));
+ }
+ qtl::bind_record(*this, std::forward<Types>(values));
+ }
+ row_handler();
+ if (PQisBusy(m_conn))
+ {
+ async_wait([this, &values, row_handler, finish_handler](const error &e)
+ {
if (e)
{
finish_handler(e);
@@ -2552,32 +2613,32 @@
{
m_res = PQgetResult(m_conn);
fetch(std::forward<Types>(values), row_handler, finish_handler);
+ } });
}
- });
+ else
+ {
+ m_res = PQgetResult(m_conn);
+ fetch(std::forward<Types>(values), row_handler, finish_handler);
+ }
+ }
+ else
+ {
+ error e;
+ m_res.verify_error<PGRES_TUPLES_OK>(e);
+ finish_handler(e);
+ }
}
else
{
- m_res = PQgetResult(m_conn);
- fetch(std::forward<Types>(values), row_handler, finish_handler);
+ finish_handler(error());
}
}
- else
- {
- error e;
- m_res.verify_error<PGRES_TUPLES_OK>(e);
- finish_handler(e);
- }
- }
- else
- {
- finish_handler(error());
- }
- }
- template<typename Handler>
- void next_result(Handler&& handler)
- {
- async_wait([this, handler](const error& e) {
+ template <typename Handler>
+ void next_result(Handler &&handler)
+ {
+ async_wait([this, handler](const error &e)
+ {
if (e)
{
handler(e);
@@ -2586,161 +2647,161 @@
{
m_res = PQgetResult(m_conn);
handler(error());
+ } });
}
- });
- }
-private:
- event* m_event;
- int m_timeout;
- template<typename Handler>
- void async_wait(Handler&& handler)
- {
- qtl::postgres::async_wait(m_event, m_conn, m_timeout, std::forward<Handler>(handler));
- }
-};
+ private:
+ event *m_event;
+ int m_timeout;
+ template <typename Handler>
+ void async_wait(Handler &&handler)
+ {
+ qtl::postgres::async_wait(m_event, m_conn, m_timeout, std::forward<Handler>(handler));
+ }
+ };
-class async_connection : public base_database, public qtl::async_connection<async_connection, async_statement>
-{
-public:
- async_connection() : m_connect_timeout(2), m_query_timeout(2)
- {
- }
- async_connection(async_connection&& src)
- : base_database(std::move(src)), m_connect_timeout(src.m_connect_timeout), m_query_timeout(src.m_query_timeout)
- {
- }
- async_connection& operator=(async_connection&& src)
- {
- if (this != &src)
+ class async_connection : public base_database, public qtl::async_connection<async_connection, async_statement>
{
- base_database::operator=(std::move(src));
- m_connect_timeout = src.m_connect_timeout;
- m_query_timeout = src.m_query_timeout;
- }
- return *this;
- }
+ public:
+ async_connection() : m_connect_timeout(2), m_query_timeout(2)
+ {
+ }
+ async_connection(async_connection &&src)
+ : base_database(std::move(src)), m_connect_timeout(src.m_connect_timeout), m_query_timeout(src.m_query_timeout)
+ {
+ }
+ async_connection &operator=(async_connection &&src)
+ {
+ if (this != &src)
+ {
+ base_database::operator=(std::move(src));
+ m_connect_timeout = src.m_connect_timeout;
+ m_query_timeout = src.m_query_timeout;
+ }
+ return *this;
+ }
- /*
- OpenHandler defines as:
- void handler(const qtl::postgres::error& e) NOEXCEPT;
- */
- template<typename EventLoop, typename OpenHandler>
- void open(EventLoop& ev, OpenHandler&& handler, const std::map<std::string, std::string>& params, bool expand_dbname = false)
- {
- std::vector<const char*> keywords;
- std::vector<const char*> values;
- keywords.reserve(params.size());
- values.reserve(params.size());
- for (auto& param : params)
- {
- keywords.push_back(param.first.data());
- values.push_back(param.second.data());
- }
- keywords.push_back(nullptr);
- values.push_back(nullptr);
- m_conn = PQconnectStartParams(keywords.data(), values.data(), expand_dbname);
- if (m_conn == nullptr)
- throw std::bad_alloc();
- if (status() == CONNECTION_BAD)
- {
- handler(error(m_conn));
- return;
- }
+ /*
+ OpenHandler defines as:
+ void handler(const qtl::postgres::error& e) NOEXCEPT;
+ */
+ template <typename EventLoop, typename OpenHandler>
+ void open(EventLoop &ev, OpenHandler &&handler, const std::map<std::string, std::string> ¶ms, bool expand_dbname = false)
+ {
+ std::vector<const char *> keywords;
+ std::vector<const char *> values;
+ keywords.reserve(params.size());
+ values.reserve(params.size());
+ for (auto ¶m : params)
+ {
+ keywords.push_back(param.first.data());
+ values.push_back(param.second.data());
+ }
+ keywords.push_back(nullptr);
+ values.push_back(nullptr);
+ m_conn = PQconnectStartParams(keywords.data(), values.data(), expand_dbname);
+ if (m_conn == nullptr)
+ throw std::bad_alloc();
+ if (status() == CONNECTION_BAD)
+ {
+ handler(error(m_conn));
+ return;
+ }
- if (PQsetnonblocking(m_conn, true)!=0)
- handler(error(m_conn));
- get_options();
- bind(ev);
- wait_connect(std::forward<OpenHandler>(handler));
- }
+ if (PQsetnonblocking(m_conn, true) != 0)
+ handler(error(m_conn));
+ get_options();
+ bind(ev);
+ wait_connect(std::forward<OpenHandler>(handler));
+ }
- template<typename EventLoop, typename OpenHandler>
- void open(EventLoop& ev, OpenHandler&& handler, const char * conninfo)
- {
- m_conn = PQconnectStart(conninfo);
- if (m_conn == nullptr)
- throw std::bad_alloc();
- if (status() == CONNECTION_BAD)
- {
- handler(error(m_conn));
- return;
- }
+ template <typename EventLoop, typename OpenHandler>
+ void open(EventLoop &ev, OpenHandler &&handler, const char *conninfo)
+ {
+ m_conn = PQconnectStart(conninfo);
+ if (m_conn == nullptr)
+ throw std::bad_alloc();
+ if (status() == CONNECTION_BAD)
+ {
+ handler(error(m_conn));
+ return;
+ }
- PQsetnonblocking(m_conn, true);
- get_options();
- bind(ev);
- wait_connect(std::forward<OpenHandler>(handler));
- }
+ PQsetnonblocking(m_conn, true);
+ get_options();
+ bind(ev);
+ wait_connect(std::forward<OpenHandler>(handler));
+ }
- template<typename OpenHandler>
- void reset(OpenHandler&& handler)
- {
- PQresetStart(m_conn);
- wait_reset(std::forward<OpenHandler>(handler));
- }
+ template <typename OpenHandler>
+ void reset(OpenHandler &&handler)
+ {
+ PQresetStart(m_conn);
+ wait_reset(std::forward<OpenHandler>(handler));
+ }
- /*
- Handler defines as:
- void handler(const qtl::mysql::error& e, uint64_t affected) NOEXCEPT;
- */
- template<typename ExecuteHandler>
- void simple_execute(ExecuteHandler&& handler, const char* query_text) NOEXCEPT
- {
- bool ok = PQsendQuery(m_conn, query_text);
- if (ok)
- {
- async_wait([this, handler](postgres::error e) mutable {
+ /*
+ Handler defines as:
+ void handler(const qtl::mysql::error& e, uint64_t affected) NOEXCEPT;
+ */
+ template <typename ExecuteHandler>
+ void simple_execute(ExecuteHandler &&handler, const char *query_text) NOEXCEPT
+ {
+ bool ok = PQsendQuery(m_conn, query_text);
+ if (ok)
+ {
+ async_wait([this, handler](postgres::error e) mutable
+ {
result res(PQgetResult(m_conn));
res.verify_error<PGRES_COMMAND_OK, PGRES_TUPLES_OK>(e);
uint64_t affected = res.affected_rows();
handler(e, affected);
while (res)
- res = PQgetResult(m_conn);
- });
- }
- else
- {
- handler(error(m_conn), 0);
- }
- }
+ res = PQgetResult(m_conn); });
+ }
+ else
+ {
+ handler(error(m_conn), 0);
+ }
+ }
- template<typename Handler>
- void auto_commit(Handler&& handler, bool on) NOEXCEPT
- {
- simple_execute(std::forward<Handler>(handler),
- on ? "SET AUTOCOMMIT TO ON" : "SET AUTOCOMMIT TO OFF");
- }
+ template <typename Handler>
+ void auto_commit(Handler &&handler, bool on) NOEXCEPT
+ {
+ simple_execute(std::forward<Handler>(handler),
+ on ? "SET AUTOCOMMIT TO ON" : "SET AUTOCOMMIT TO OFF");
+ }
- template<typename Handler>
- void begin_transaction(Handler&& handler) NOEXCEPT
- {
- simple_execute(std::forward<Handler>(handler), "BEGIN");
- }
+ template <typename Handler>
+ void begin_transaction(Handler &&handler) NOEXCEPT
+ {
+ simple_execute(std::forward<Handler>(handler), "BEGIN");
+ }
- template<typename Handler>
- void rollback(Handler&& handler) NOEXCEPT
- {
- simple_execute(std::forward<Handler>(handler), "ROLLBACK");
- }
+ template <typename Handler>
+ void rollback(Handler &&handler) NOEXCEPT
+ {
+ simple_execute(std::forward<Handler>(handler), "ROLLBACK");
+ }
- template<typename Handler>
- void commit(Handler&& handler) NOEXCEPT
- {
- simple_execute(std::forward<Handler>(handler), "COMMIT");
- }
+ template <typename Handler>
+ void commit(Handler &&handler) NOEXCEPT
+ {
+ simple_execute(std::forward<Handler>(handler), "COMMIT");
+ }
- /*
- ResultHandler defines as:
- void result_handler(const qtl::postgres::error& e) NOEXCEPT;
- */
- template<typename RowHandler, typename ResultHandler>
- void simple_query(const char* query, RowHandler&& row_handler, ResultHandler&& result_handler) NOEXCEPT
- {
- bool ok = PQsendQuery(m_conn, query);
- if (ok)
- {
- async_wait([this, row_handler, result_handler](postgres::error e) mutable {
+ /*
+ ResultHandler defines as:
+ void result_handler(const qtl::postgres::error& e) NOEXCEPT;
+ */
+ template <typename RowHandler, typename ResultHandler>
+ void simple_query(const char *query, RowHandler &&row_handler, ResultHandler &&result_handler) NOEXCEPT
+ {
+ bool ok = PQsendQuery(m_conn, query);
+ if (ok)
+ {
+ async_wait([this, row_handler, result_handler](postgres::error e) mutable
+ {
result res(PQgetResult(m_conn));
res.verify_error<PGRES_COMMAND_OK, PGRES_TUPLES_OK>(e);
if (e)
@@ -2755,144 +2816,140 @@
stmt.fetch_all(row_handler);
res = PQgetResult(m_conn);
}
- result_handler(e, affected);
- });
- }
- else
- {
- result_handler(error(m_conn), 0);
- }
- }
-
- template<typename Handler>
- void open_command(const char* query_text, size_t /*text_length*/, Handler&& handler)
- {
- std::shared_ptr<async_statement> stmt = std::make_shared<async_statement>(*this);
- stmt->open([stmt, handler](const postgres::error& e) mutable {
- handler(e, stmt);
- }, query_text, 0);
- }
-
- template<typename Handler>
- void is_alive(Handler&& handler) NOEXCEPT
- {
- simple_execute(std::forward<Handler>(handler), "");
- }
-
- socket_type socket() const NOEXCEPT { return PQsocket(m_conn); }
-
- int connect_timeout() const { return m_connect_timeout; }
- void connect_timeout(int timeout) { m_connect_timeout = timeout; }
- int query_timeout() const { return m_query_timeout; }
- void query_timeout(int timeout) { m_query_timeout = timeout; }
-
-private:
- int m_connect_timeout;
- int m_query_timeout;
-
- void get_options()
- {
- PQconninfoOption* options = PQconninfo(m_conn);
- m_connect_timeout = 2;
- for (PQconninfoOption* option = options; option; option++)
- {
- if (strcmp(option->keyword, "connect_timeout") == 0)
- {
- if (option->val)
- m_connect_timeout = atoi(option->val);
- break;
+ result_handler(e, affected); });
+ }
+ else
+ {
+ result_handler(error(m_conn), 0);
+ }
}
- }
- PQconninfoFree(options);
- }
- template<typename OpenHandler>
- void wait_connect(OpenHandler&& handler) NOEXCEPT
- {
- PostgresPollingStatusType status = PQconnectPoll(m_conn);
- switch (status)
- {
- case PGRES_POLLING_READING:
- case PGRES_POLLING_WRITING:
- m_event_handler->set_io_handler(event_flags(status), m_connect_timeout,
- [this, handler](int flags) mutable {
- if (flags&event::ef_timeout)
+ template <typename Handler>
+ void open_command(const char *query_text, size_t /*text_length*/, Handler &&handler)
+ {
+ std::shared_ptr<async_statement> stmt = std::make_shared<async_statement>(*this);
+ stmt->open([stmt, handler](const postgres::error &e) mutable
+ { handler(e, stmt); }, query_text, 0);
+ }
+
+ template <typename Handler>
+ void is_alive(Handler &&handler) NOEXCEPT
+ {
+ simple_execute(std::forward<Handler>(handler), "");
+ }
+
+ socket_type socket() const NOEXCEPT { return PQsocket(m_conn); }
+
+ int connect_timeout() const { return m_connect_timeout; }
+ void connect_timeout(int timeout) { m_connect_timeout = timeout; }
+ int query_timeout() const { return m_query_timeout; }
+ void query_timeout(int timeout) { m_query_timeout = timeout; }
+
+ private:
+ int m_connect_timeout;
+ int m_query_timeout;
+
+ void get_options()
+ {
+ PQconninfoOption *options = PQconninfo(m_conn);
+ m_connect_timeout = 2;
+ for (PQconninfoOption *option = options; option; option++)
{
- handler(postgres::timeout());
+ if (strcmp(option->keyword, "connect_timeout") == 0)
+ {
+ if (option->val)
+ m_connect_timeout = atoi(option->val);
+ break;
+ }
}
- else if(flags&(event::ef_read|event::ef_write | event::ef_exception))
- wait_connect(std::forward<OpenHandler>(handler));
- });
- break;
- case PGRES_POLLING_FAILED:
- handler(postgres::error(handle()));
- break;
- case PGRES_POLLING_OK:
- //PQsetnonblocking(m_conn, true);
- handler(postgres::error());
- }
- }
+ PQconninfoFree(options);
+ }
- template<typename OpenHandler>
- void wait_reset(OpenHandler&& handler) NOEXCEPT
- {
- PostgresPollingStatusType status = PQresetPoll(m_conn);
- switch (status)
- {
- case PGRES_POLLING_READING:
- case PGRES_POLLING_WRITING:
- m_event_handler->set_io_handler(event_flags(status), m_connect_timeout,
- [this, handler](int flags) mutable {
- if (flags&event::ef_timeout)
+ template <typename OpenHandler>
+ void wait_connect(OpenHandler &&handler) NOEXCEPT
+ {
+ PostgresPollingStatusType status = PQconnectPoll(m_conn);
+ switch (status)
{
- handler(postgres::timeout());
+ case PGRES_POLLING_READING:
+ case PGRES_POLLING_WRITING:
+ m_event_handler->set_io_handler(event_flags(status), m_connect_timeout,
+ [this, handler](int flags) mutable
+ {
+ if (flags & event::ef_timeout)
+ {
+ handler(postgres::timeout());
+ }
+ else if (flags & (event::ef_read | event::ef_write | event::ef_exception))
+ wait_connect(std::forward<OpenHandler>(handler));
+ });
+ break;
+ case PGRES_POLLING_FAILED:
+ handler(postgres::error(handle()));
+ break;
+ case PGRES_POLLING_OK:
+ // PQsetnonblocking(m_conn, true);
+ handler(postgres::error());
}
- else if (flags&(event::ef_read | event::ef_write | event::ef_exception))
- wait_reset(std::forward<OpenHandler>(handler));
- });
- break;
- case PGRES_POLLING_FAILED:
- handler(postgres::error(m_conn));
- break;
- case PGRES_POLLING_OK:
- handler(postgres::error());
+ }
+
+ template <typename OpenHandler>
+ void wait_reset(OpenHandler &&handler) NOEXCEPT
+ {
+ PostgresPollingStatusType status = PQresetPoll(m_conn);
+ switch (status)
+ {
+ case PGRES_POLLING_READING:
+ case PGRES_POLLING_WRITING:
+ m_event_handler->set_io_handler(event_flags(status), m_connect_timeout,
+ [this, handler](int flags) mutable
+ {
+ if (flags & event::ef_timeout)
+ {
+ handler(postgres::timeout());
+ }
+ else if (flags & (event::ef_read | event::ef_write | event::ef_exception))
+ wait_reset(std::forward<OpenHandler>(handler));
+ });
+ break;
+ case PGRES_POLLING_FAILED:
+ handler(postgres::error(m_conn));
+ break;
+ case PGRES_POLLING_OK:
+ handler(postgres::error());
+ }
+ }
+
+ template <typename Handler>
+ void async_wait(Handler &&handler)
+ {
+ qtl::postgres::async_wait(event(), m_conn, m_query_timeout, std::forward<Handler>(handler));
+ }
+ };
+
+ inline async_statement::async_statement(async_connection &db)
+ : base_statement(static_cast<base_database &>(db))
+ {
+ m_event = db.event();
+ m_timeout = db.query_timeout();
}
+
+ typedef qtl::transaction<database> transaction;
+
+ template <typename Record>
+ using query_iterator = qtl::query_iterator<statement, Record>;
+
+ template <typename Record>
+ using query_result = qtl::query_result<statement, Record>;
+
+ inline base_statement::base_statement(base_database &db) : m_res(nullptr)
+ {
+ m_conn = db.handle();
+ m_res = nullptr;
+ }
+
}
- template<typename Handler>
- void async_wait(Handler&& handler)
- {
- qtl::postgres::async_wait(event(), m_conn, m_query_timeout, std::forward<Handler>(handler));
- }
-
-};
-
-inline async_statement::async_statement(async_connection& db)
- : base_statement(static_cast<base_database&>(db))
-{
- m_event = db.event();
- m_timeout = db.query_timeout();
}
-
-
-typedef qtl::transaction<database> transaction;
-
-template<typename Record>
-using query_iterator = qtl::query_iterator<statement, Record>;
-
-template<typename Record>
-using query_result = qtl::query_result<statement, Record>;
-
-inline base_statement::base_statement(base_database& db) : m_res(nullptr)
-{
- m_conn = db.handle();
- m_res = nullptr;
-}
-
-}
-
-}
-
#endif //_SQL_POSTGRES_H_
-
diff --git a/include/qtl_postgres_pool.hpp b/include/qtl_postgres_pool.hpp
index 815ee3c..17fdfa1 100644
--- a/include/qtl_postgres_pool.hpp
+++ b/include/qtl_postgres_pool.hpp
@@ -7,64 +7,65 @@
namespace qtl
{
-namespace postgres
-{
-
-class database_pool : public qtl::database_pool<database>
-{
-public:
- database_pool() : m_port(0) { }
- virtual ~database_pool() { }
- virtual database* new_database() throw() override
+ namespace postgres
{
- database* db=new database;
- if(!db->open(m_host.data(), m_user.data(), m_password.data(), m_port, m_database.data()))
+
+ class database_pool : public qtl::database_pool<database>
{
- delete db;
- db=NULL;
- }
- else
+ public:
+ database_pool() : m_port(0) {}
+ virtual ~database_pool() {}
+ virtual database *new_database() throw() override
+ {
+ database *db = new database;
+ if (!db->open(m_host.data(), m_user.data(), m_password.data(), m_port, m_database.data()))
+ {
+ delete db;
+ db = NULL;
+ }
+ else
+ {
+ PQsetClientEncoding(db->handle(), "UTF8");
+ }
+ return db;
+ }
+
+ protected:
+ std::string m_host;
+ unsigned short m_port;
+ std::string m_database;
+ std::string m_user;
+ std::string m_password;
+ };
+
+ template <typename EventLoop>
+ class async_pool : public qtl::async_pool<async_pool<EventLoop>, EventLoop, async_connection>
{
- PQsetClientEncoding(db->handle(), "UTF8");
- }
- return db;
- }
+ typedef qtl::async_pool<async_pool<EventLoop>, EventLoop, async_connection> base_class;
-protected:
- std::string m_host;
- unsigned short m_port;
- std::string m_database;
- std::string m_user;
- std::string m_password;
-};
+ public:
+ async_pool(EventLoop &ev) : base_class(ev) {}
+ virtual ~async_pool() {}
-template<typename EventLoop>
-class async_pool : public qtl::async_pool<async_pool<EventLoop>, EventLoop, async_connection>
-{
- typedef qtl::async_pool<async_pool<EventLoop>, EventLoop, async_connection> base_class;
-public:
- async_pool(EventLoop& ev) : base_class(ev) { }
- virtual ~async_pool() { }
-
- template<typename Handler>
- void new_connection(EventLoop& ev, Handler&& handler) throw()
- {
- async_connection* db = new async_connection;
- db->open(ev, [this, handler, db](const postgres::error& e) mutable {
+ template <typename Handler>
+ void new_connection(EventLoop &ev, Handler &&handler) throw()
+ {
+ async_connection *db = new async_connection;
+ db->open(ev, [this, handler, db](const postgres::error &e) mutable
+ {
if (e)
{
delete db;
db = nullptr;
}
- handler(e, db);
- }, m_params);
+ handler(e, db); }, m_params);
+ }
+
+ protected:
+ std::map<std::string, std::string> m_params;
+ };
+
}
-
-protected:
- std::map<std::string, std::string> m_params;
-};
-
-}
}
diff --git a/include/qtl_sqlite.hpp b/include/qtl_sqlite.hpp
index 3a0482f..658c3c9 100644
--- a/include/qtl_sqlite.hpp
+++ b/include/qtl_sqlite.hpp
@@ -10,1123 +10,1124 @@
namespace qtl
{
-namespace sqlite
-{
+ namespace sqlite
+ {
-class error : public std::exception
-{
-public:
- explicit error(int error_code) : m_errno(error_code)
- {
- m_errmsg=sqlite3_errstr(error_code);
- }
- explicit error(sqlite3* db)
- {
- m_errno=sqlite3_errcode(db);
- m_errmsg=sqlite3_errmsg(db);
- }
- error(const error& src) = default;
- virtual ~error() throw() { }
- virtual const char* what() const throw() override { return m_errmsg; }
- int code() const throw() { return m_errno; }
-
-private:
- int m_errno;
- const char* m_errmsg;
-};
-
-class statement final
-{
-public:
- statement() : m_stmt(NULL), m_fetch_result(SQLITE_OK) { }
- statement(const statement&) = delete;
- statement(statement&& src)
- : m_stmt(src.m_stmt), m_fetch_result(src.m_fetch_result),
- m_tail_text(std::forward<std::string>(src.m_tail_text))
- {
- src.m_stmt=NULL;
- src.m_fetch_result=SQLITE_OK;
- }
- statement& operator=(const statement&) = delete;
- statement& operator=(statement&& src)
- {
- if(this!=&src)
+ class error : public std::exception
{
- m_stmt=src.m_stmt;
- m_fetch_result=src.m_fetch_result;
- m_tail_text=std::forward<std::string>(src.m_tail_text);
- src.m_stmt=NULL;
- src.m_fetch_result=SQLITE_OK;
- }
- return *this;
- }
- ~statement()
- {
- close();
- }
+ public:
+ explicit error(int error_code) : m_errno(error_code)
+ {
+ m_errmsg = sqlite3_errstr(error_code);
+ }
+ explicit error(sqlite3 *db)
+ {
+ m_errno = sqlite3_errcode(db);
+ m_errmsg = sqlite3_errmsg(db);
+ }
+ error(const error &src) = default;
+ virtual ~error() throw() {}
+ virtual const char *what() const throw() override { return m_errmsg; }
+ int code() const throw() { return m_errno; }
- void open(sqlite3* db, const char* query_text, size_t text_length=-1)
- {
- const char* tail=NULL;
- close();
- verify_error(sqlite3_prepare_v2(db, query_text, (int)text_length, &m_stmt, &tail));
- if(tail!=NULL)
- {
- if(text_length==-1)
- m_tail_text.assign(tail);
- else
- m_tail_text.assign(tail, query_text+text_length);
- }
- else
- m_tail_text.clear();
- }
+ private:
+ int m_errno;
+ const char *m_errmsg;
+ };
- void close()
- {
- if(m_stmt)
+ class statement final
{
- sqlite3_finalize(m_stmt);
- m_stmt=NULL;
- }
- }
+ public:
+ statement() : m_stmt(NULL), m_fetch_result(SQLITE_OK) {}
+ statement(const statement &) = delete;
+ statement(statement &&src)
+ : m_stmt(src.m_stmt), m_fetch_result(src.m_fetch_result),
+ m_tail_text(std::forward<std::string>(src.m_tail_text))
+ {
+ src.m_stmt = NULL;
+ src.m_fetch_result = SQLITE_OK;
+ }
+ statement &operator=(const statement &) = delete;
+ statement &operator=(statement &&src)
+ {
+ if (this != &src)
+ {
+ m_stmt = src.m_stmt;
+ m_fetch_result = src.m_fetch_result;
+ m_tail_text = std::forward<std::string>(src.m_tail_text);
+ src.m_stmt = NULL;
+ src.m_fetch_result = SQLITE_OK;
+ }
+ return *this;
+ }
+ ~statement()
+ {
+ close();
+ }
- void bind_param(int index, int value)
- {
- verify_error(sqlite3_bind_int(m_stmt, index+1, value));
- }
- void bind_param(int index, int64_t value)
- {
- verify_error(sqlite3_bind_int64(m_stmt, index+1, value));
- }
- void bind_param(int index, double value)
- {
- verify_error(sqlite3_bind_double(m_stmt, index+1, value));
- }
- void bind_param(int index, const char* value, size_t n=-1)
- {
- if(value)
- verify_error(sqlite3_bind_text(m_stmt, index+1, value, (int)n, NULL));
- else
- verify_error(sqlite3_bind_null(m_stmt, index+1));
- }
- void bind_param(int index, const wchar_t* value, size_t n=-1)
- {
- if(value)
- verify_error(sqlite3_bind_text16(m_stmt, index+1, value, (int)n, NULL));
- else
- verify_error(sqlite3_bind_null(m_stmt, index+1));
- }
- void bind_param(int index, const std::string& value)
- {
- bind_param(index, value.data(), value.size());
- }
- void bind_param(int index, const std::wstring& value)
- {
- bind_param(index, value.data(), value.size());
- }
- void bind_param(int index, const const_blob_data& value)
- {
- if(value.size)
- {
- if(value.data)
- verify_error(sqlite3_bind_blob(m_stmt, index+1, value.data, (int)value.size, NULL));
- else
- verify_error(sqlite3_bind_zeroblob(m_stmt, index+1, (int)value.size));
- }
- else
- verify_error(sqlite3_bind_null(m_stmt, index+1));
- }
- void bind_zero_blob(int index, int n)
- {
- verify_error(sqlite3_bind_zeroblob(m_stmt, index+1, (int)n));
- }
- //void bind_zero_blob(int index, sqlite3_uint64 n)
- //{
- // verify_error(sqlite3_bind_zeroblob64(m_stmt, index+1, (int)n));
- //}
- void bind_param(int index, qtl::null)
- {
- verify_error(sqlite3_bind_null(m_stmt, index+1));
- }
- void bind_param(int index, std::nullptr_t)
- {
- verify_error(sqlite3_bind_null(m_stmt, index+1));
- }
- int get_parameter_count() const
- {
- return sqlite3_bind_parameter_count(m_stmt);
- }
- const char* get_parameter_name(int i) const
- {
- return sqlite3_bind_parameter_name(m_stmt, i);
- }
- int get_parameter_index(const char* param_name) const
- {
- return sqlite3_bind_parameter_index(m_stmt, param_name);
- }
+ void open(sqlite3 *db, const char *query_text, size_t text_length = -1)
+ {
+ const char *tail = NULL;
+ close();
+ verify_error(sqlite3_prepare_v2(db, query_text, (int)text_length, &m_stmt, &tail));
+ if (tail != NULL)
+ {
+ if (text_length == -1)
+ m_tail_text.assign(tail);
+ else
+ m_tail_text.assign(tail, query_text + text_length);
+ }
+ else
+ m_tail_text.clear();
+ }
- template<class Type>
- void bind_field(size_t index, Type&& value)
- {
- get_value((int)index, std::forward<Type>(value));
- }
- template<class Type>
- void bind_field(size_t index, qtl::indicator<Type>&& value)
- {
- int type=get_column_type(index);
- value.length=0;
- value.is_truncated=false;
- qtl::bind_field(*this, index, value.data);
- if(type==SQLITE_NULL)
- {
- value.is_null=true;
- }
- else
- {
- value.is_null=false;
- if(type==SQLITE_TEXT || type==SQLITE_BLOB)
- value.length=sqlite3_column_bytes(m_stmt, index);
- }
- }
- void bind_field(size_t index, char* value, size_t length)
- {
- size_t col_length=get_column_length((int)index);
- if(col_length>0)
- strncpy(value, (const char*)sqlite3_column_text(m_stmt, (int)index), std::min(length, col_length+1));
- else
- memset(value, 0, length*sizeof(char));
- }
- void bind_field(size_t index, wchar_t* value, size_t length)
- {
- size_t col_length=sqlite3_column_bytes16(m_stmt, (int)index);
- if(col_length>0)
- wcsncpy(value, (const wchar_t*)sqlite3_column_text16(m_stmt, (int)index), std::min(length, col_length+1));
- else
- memset(value, 0, length*sizeof(wchar_t));
- }
- template<size_t N>
- void bind_field(size_t index, char (&&value)[N])
- {
- bind_field(index, value, N);
- }
- template<size_t N>
- void bind_field(size_t index, wchar_t (&&value)[N])
- {
- bind_field(index, value, N);
- }
- template<size_t N>
- void bind_field(size_t index, std::array<char, N>&& value)
- {
- bind_field(index, value.data(), value.size());
- }
- template<size_t N>
- void bind_field(size_t index, std::array<wchar_t, N>&& value)
- {
- bind_field(index, value.data(), value.size());
- }
+ void close()
+ {
+ if (m_stmt)
+ {
+ sqlite3_finalize(m_stmt);
+ m_stmt = NULL;
+ }
+ }
+
+ void bind_param(int index, int value)
+ {
+ verify_error(sqlite3_bind_int(m_stmt, index + 1, value));
+ }
+ void bind_param(int index, int64_t value)
+ {
+ verify_error(sqlite3_bind_int64(m_stmt, index + 1, value));
+ }
+ void bind_param(int index, double value)
+ {
+ verify_error(sqlite3_bind_double(m_stmt, index + 1, value));
+ }
+ void bind_param(int index, const char *value, size_t n = -1)
+ {
+ if (value)
+ verify_error(sqlite3_bind_text(m_stmt, index + 1, value, (int)n, NULL));
+ else
+ verify_error(sqlite3_bind_null(m_stmt, index + 1));
+ }
+ void bind_param(int index, const wchar_t *value, size_t n = -1)
+ {
+ if (value)
+ verify_error(sqlite3_bind_text16(m_stmt, index + 1, value, (int)n, NULL));
+ else
+ verify_error(sqlite3_bind_null(m_stmt, index + 1));
+ }
+ void bind_param(int index, const std::string &value)
+ {
+ bind_param(index, value.data(), value.size());
+ }
+ void bind_param(int index, const std::wstring &value)
+ {
+ bind_param(index, value.data(), value.size());
+ }
+ void bind_param(int index, const const_blob_data &value)
+ {
+ if (value.size)
+ {
+ if (value.data)
+ verify_error(sqlite3_bind_blob(m_stmt, index + 1, value.data, (int)value.size, NULL));
+ else
+ verify_error(sqlite3_bind_zeroblob(m_stmt, index + 1, (int)value.size));
+ }
+ else
+ verify_error(sqlite3_bind_null(m_stmt, index + 1));
+ }
+ void bind_zero_blob(int index, int n)
+ {
+ verify_error(sqlite3_bind_zeroblob(m_stmt, index + 1, (int)n));
+ }
+ // void bind_zero_blob(int index, sqlite3_uint64 n)
+ //{
+ // verify_error(sqlite3_bind_zeroblob64(m_stmt, index+1, (int)n));
+ // }
+ void bind_param(int index, qtl::null)
+ {
+ verify_error(sqlite3_bind_null(m_stmt, index + 1));
+ }
+ void bind_param(int index, std::nullptr_t)
+ {
+ verify_error(sqlite3_bind_null(m_stmt, index + 1));
+ }
+ int get_parameter_count() const
+ {
+ return sqlite3_bind_parameter_count(m_stmt);
+ }
+ const char *get_parameter_name(int i) const
+ {
+ return sqlite3_bind_parameter_name(m_stmt, i);
+ }
+ int get_parameter_index(const char *param_name) const
+ {
+ return sqlite3_bind_parameter_index(m_stmt, param_name);
+ }
+
+ template <class Type>
+ void bind_field(size_t index, Type &&value)
+ {
+ get_value((int)index, std::forward<Type>(value));
+ }
+ template <class Type>
+ void bind_field(size_t index, qtl::indicator<Type> &&value)
+ {
+ int type = get_column_type(index);
+ value.length = 0;
+ value.is_truncated = false;
+ qtl::bind_field(*this, index, value.data);
+ if (type == SQLITE_NULL)
+ {
+ value.is_null = true;
+ }
+ else
+ {
+ value.is_null = false;
+ if (type == SQLITE_TEXT || type == SQLITE_BLOB)
+ value.length = sqlite3_column_bytes(m_stmt, index);
+ }
+ }
+ void bind_field(size_t index, char *value, size_t length)
+ {
+ size_t col_length = get_column_length((int)index);
+ if (col_length > 0)
+ strncpy(value, (const char *)sqlite3_column_text(m_stmt, (int)index), std::min(length, col_length + 1));
+ else
+ memset(value, 0, length * sizeof(char));
+ }
+ void bind_field(size_t index, wchar_t *value, size_t length)
+ {
+ size_t col_length = sqlite3_column_bytes16(m_stmt, (int)index);
+ if (col_length > 0)
+ wcsncpy(value, (const wchar_t *)sqlite3_column_text16(m_stmt, (int)index), std::min(length, col_length + 1));
+ else
+ memset(value, 0, length * sizeof(wchar_t));
+ }
+ template <size_t N>
+ void bind_field(size_t index, char (&&value)[N])
+ {
+ bind_field(index, value, N);
+ }
+ template <size_t N>
+ void bind_field(size_t index, wchar_t (&&value)[N])
+ {
+ bind_field(index, value, N);
+ }
+ template <size_t N>
+ void bind_field(size_t index, std::array<char, N> &&value)
+ {
+ bind_field(index, value.data(), value.size());
+ }
+ template <size_t N>
+ void bind_field(size_t index, std::array<wchar_t, N> &&value)
+ {
+ bind_field(index, value.data(), value.size());
+ }
#ifdef _QTL_ENABLE_CPP17
- template<typename T>
- inline void bind_field(size_t index, std::optional<T>&& value)
- {
- int type = get_column_type(index);
- if (type == SQLITE_NULL)
- {
- value.reset();
- }
- else
- {
- qtl::bind_field(*this, index, *value);
- }
- }
+ template <typename T>
+ inline void bind_field(size_t index, std::optional<T> &&value)
+ {
+ int type = get_column_type(index);
+ if (type == SQLITE_NULL)
+ {
+ value.reset();
+ }
+ else
+ {
+ qtl::bind_field(*this, index, *value);
+ }
+ }
- inline void bind_field(size_t index, std::any&& value)
- {
- int type = get_column_type(index);
- switch(type)
- {
- case SQLITE_NULL:
- value.reset();
- case SQLITE_INTEGER:
- value = sqlite3_column_int64(m_stmt, index);
- break;
- case SQLITE_FLOAT:
- value = sqlite3_column_double(m_stmt, index);
- break;
- case SQLITE_TEXT:
- value.emplace<std::string_view>((const char*)sqlite3_column_text(m_stmt, index), sqlite3_column_bytes(m_stmt, index));
- break;
- case SQLITE_BLOB:
- value.emplace<const_blob_data>(sqlite3_column_text(m_stmt, index), sqlite3_column_bytes(m_stmt, index));
- break;
- default:
- throw sqlite::error(SQLITE_MISMATCH);
- }
- }
+ inline void bind_field(size_t index, std::any &&value)
+ {
+ int type = get_column_type(index);
+ switch (type)
+ {
+ case SQLITE_NULL:
+ value.reset();
+ case SQLITE_INTEGER:
+ value = sqlite3_column_int64(m_stmt, index);
+ break;
+ case SQLITE_FLOAT:
+ value = sqlite3_column_double(m_stmt, index);
+ break;
+ case SQLITE_TEXT:
+ value.emplace<std::string_view>((const char *)sqlite3_column_text(m_stmt, index), sqlite3_column_bytes(m_stmt, index));
+ break;
+ case SQLITE_BLOB:
+ value.emplace<const_blob_data>(sqlite3_column_text(m_stmt, index), sqlite3_column_bytes(m_stmt, index));
+ break;
+ default:
+ throw sqlite::error(SQLITE_MISMATCH);
+ }
+ }
#endif // C++17
- size_t find_field(const char* name) const
- {
- size_t count=get_column_count();
- for(size_t i=0; i!=count; i++)
- {
- if(strcmp(get_column_name(i), name)==0)
- return i;
- }
- return -1;
- }
-
- bool fetch()
- {
- m_fetch_result=sqlite3_step(m_stmt);
- switch(m_fetch_result)
- {
- case SQLITE_ROW:
- return true;
- case SQLITE_DONE:
- return false;
- default:
- throw sqlite::error(m_fetch_result);
- }
- }
- int get_column_count() const
- {
- return sqlite3_column_count(m_stmt);
- }
- const char* get_column_name(int col) const
- {
- return sqlite3_column_name(m_stmt, col);
- }
- void get_value(int col, int&& value) const
- {
- value=sqlite3_column_int(m_stmt, col);
- }
- void get_value(int col, int64_t&& value) const
- {
- value=sqlite3_column_int64(m_stmt, col);
- }
- void get_value(int col, double&& value) const
- {
- value=sqlite3_column_double(m_stmt, col);
- }
- const unsigned char* get_value(int col) const
- {
- return sqlite3_column_text(m_stmt, col);
- }
-
- template<typename CharT>
- const CharT* get_text_value(int col) const;
-
- template<typename T>
- void get_value(int col, qtl::bind_string_helper<T>&& value) const
- {
- typedef typename qtl::bind_string_helper<T>::char_type char_type;
- int bytes=sqlite3_column_bytes(m_stmt, col);
- if(bytes>0)
- value.assign(get_text_value<char_type>(col), bytes/sizeof(char_type));
- else
- value.clear();
- }
- void get_value(int col, const_blob_data&& value) const
- {
- value.data=sqlite3_column_blob(m_stmt, col);
- value.size=sqlite3_column_bytes(m_stmt, col);
- }
- void get_value(int col, blob_data&& value) const
- {
- const void* data=sqlite3_column_blob(m_stmt, col);
- size_t size=sqlite3_column_bytes(m_stmt, col);
- if(value.size<size)
- throw std::out_of_range("no enough buffer to receive blob data.");
- memcpy(value.data, data, size);
- value.size=size;
- }
- void get_value(int col, std::ostream&& value) const
- {
- const void* data=sqlite3_column_blob(m_stmt, col);
- size_t size=sqlite3_column_bytes(m_stmt, col);
- if(size>0)
- value.write((const char*)data, size);
- }
-
- int get_column_length(int col) const
- {
- return sqlite3_column_bytes(m_stmt, col);
- }
- int get_column_type(int col) const
- {
- return sqlite3_column_type(m_stmt, col);
- }
- void clear_bindings()
- {
- sqlite3_clear_bindings(m_stmt);
- }
- void reset()
- {
- sqlite3_reset(m_stmt);
- }
-
- template<typename Types>
- void execute(const Types& params)
- {
- unsigned long count=get_parameter_count();
- if(count>0)
- {
- qtl::bind_params(*this, params);
- }
- fetch();
- }
-
- template<typename Types>
- bool fetch(Types&& values)
- {
- bool result=false;
- if(m_fetch_result==SQLITE_OK)
- fetch();
- if(m_fetch_result==SQLITE_ROW)
- {
- result=true;
- qtl::bind_record(*this, std::forward<Types>(values));
- m_fetch_result=SQLITE_OK;
- }
- return result;
- }
-
- bool next_result()
- {
- sqlite3* db=sqlite3_db_handle(m_stmt);
- int count=0;
- do
- {
- trim_string(m_tail_text, " \t\r\n");
- if(!m_tail_text.empty())
+ size_t find_field(const char *name) const
{
- open(db, m_tail_text.data(), m_tail_text.size());
- count=sqlite3_column_count(m_stmt);
- m_fetch_result=SQLITE_OK;
+ size_t count = get_column_count();
+ for (size_t i = 0; i != count; i++)
+ {
+ if (strcmp(get_column_name(i), name) == 0)
+ return i;
+ }
+ return -1;
}
- }while(!m_tail_text.empty() && count==0);
- return count>0;;
- }
- int affetced_rows() const
- {
- sqlite3* db=sqlite3_db_handle(m_stmt);
- return db ? sqlite3_changes(db) : 0;
- }
+ bool fetch()
+ {
+ m_fetch_result = sqlite3_step(m_stmt);
+ switch (m_fetch_result)
+ {
+ case SQLITE_ROW:
+ return true;
+ case SQLITE_DONE:
+ return false;
+ default:
+ throw sqlite::error(m_fetch_result);
+ }
+ }
+ int get_column_count() const
+ {
+ return sqlite3_column_count(m_stmt);
+ }
+ const char *get_column_name(int col) const
+ {
+ return sqlite3_column_name(m_stmt, col);
+ }
+ void get_value(int col, int &&value) const
+ {
+ value = sqlite3_column_int(m_stmt, col);
+ }
+ void get_value(int col, int64_t &&value) const
+ {
+ value = sqlite3_column_int64(m_stmt, col);
+ }
+ void get_value(int col, double &&value) const
+ {
+ value = sqlite3_column_double(m_stmt, col);
+ }
+ const unsigned char *get_value(int col) const
+ {
+ return sqlite3_column_text(m_stmt, col);
+ }
- int64_t insert_id() const
- {
- sqlite3* db=sqlite3_db_handle(m_stmt);
- return db ? sqlite3_last_insert_rowid(db) : 0;
- }
+ template <typename CharT>
+ const CharT *get_text_value(int col) const;
-protected:
- sqlite3_stmt* m_stmt;
- std::string m_tail_text;
-
- int m_fetch_result;
- void verify_error(int e)
- {
- if(e!=SQLITE_OK) throw error(e);
- }
-};
+ template <typename T>
+ void get_value(int col, qtl::bind_string_helper<T> &&value) const
+ {
+ typedef typename qtl::bind_string_helper<T>::char_type char_type;
+ int bytes = sqlite3_column_bytes(m_stmt, col);
+ if (bytes > 0)
+ value.assign(get_text_value<char_type>(col), bytes / sizeof(char_type));
+ else
+ value.clear();
+ }
+ void get_value(int col, const_blob_data &&value) const
+ {
+ value.data = sqlite3_column_blob(m_stmt, col);
+ value.size = sqlite3_column_bytes(m_stmt, col);
+ }
+ void get_value(int col, blob_data &&value) const
+ {
+ const void *data = sqlite3_column_blob(m_stmt, col);
+ size_t size = sqlite3_column_bytes(m_stmt, col);
+ if (value.size < size)
+ throw std::out_of_range("no enough buffer to receive blob data.");
+ memcpy(value.data, data, size);
+ value.size = size;
+ }
+ void get_value(int col, std::ostream &&value) const
+ {
+ const void *data = sqlite3_column_blob(m_stmt, col);
+ size_t size = sqlite3_column_bytes(m_stmt, col);
+ if (size > 0)
+ value.write((const char *)data, size);
+ }
-class database final : public qtl::base_database<database, statement>
-{
-public:
- typedef sqlite::error exception_type;
+ int get_column_length(int col) const
+ {
+ return sqlite3_column_bytes(m_stmt, col);
+ }
+ int get_column_type(int col) const
+ {
+ return sqlite3_column_type(m_stmt, col);
+ }
+ void clear_bindings()
+ {
+ sqlite3_clear_bindings(m_stmt);
+ }
+ void reset()
+ {
+ sqlite3_reset(m_stmt);
+ }
- database() : m_db(NULL) { }
- ~database() { close(); }
- database(const database&) = delete;
- database(database&& src)
- {
- m_db=src.m_db;
- src.m_db=NULL;
- }
- database& operator=(const database&) = delete;
- database& operator=(database&& src)
- {
- if(this!=&src)
+ template <typename Types>
+ void execute(const Types ¶ms)
+ {
+ unsigned long count = get_parameter_count();
+ if (count > 0)
+ {
+ qtl::bind_params(*this, params);
+ }
+ fetch();
+ }
+
+ template <typename Types>
+ bool fetch(Types &&values)
+ {
+ bool result = false;
+ if (m_fetch_result == SQLITE_OK)
+ fetch();
+ if (m_fetch_result == SQLITE_ROW)
+ {
+ result = true;
+ qtl::bind_record(*this, std::forward<Types>(values));
+ m_fetch_result = SQLITE_OK;
+ }
+ return result;
+ }
+
+ bool next_result()
+ {
+ sqlite3 *db = sqlite3_db_handle(m_stmt);
+ int count = 0;
+ do
+ {
+ trim_string(m_tail_text, " \t\r\n");
+ if (!m_tail_text.empty())
+ {
+ open(db, m_tail_text.data(), m_tail_text.size());
+ count = sqlite3_column_count(m_stmt);
+ m_fetch_result = SQLITE_OK;
+ }
+ } while (!m_tail_text.empty() && count == 0);
+ return count > 0;
+ ;
+ }
+
+ int affetced_rows() const
+ {
+ sqlite3 *db = sqlite3_db_handle(m_stmt);
+ return db ? sqlite3_changes(db) : 0;
+ }
+
+ int64_t insert_id() const
+ {
+ sqlite3 *db = sqlite3_db_handle(m_stmt);
+ return db ? sqlite3_last_insert_rowid(db) : 0;
+ }
+
+ protected:
+ sqlite3_stmt *m_stmt;
+ std::string m_tail_text;
+
+ int m_fetch_result;
+ void verify_error(int e)
+ {
+ if (e != SQLITE_OK)
+ throw error(e);
+ }
+ };
+
+ class database final : public qtl::base_database<database, statement>
{
- close();
- m_db=src.m_db;
- src.m_db=NULL;
- }
- return *this;
- }
+ public:
+ typedef sqlite::error exception_type;
- void open(const char *filename, int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE)
- {
- int result=sqlite3_open_v2(filename, &m_db, flags, NULL);
- if(result!=SQLITE_OK)
- throw sqlite::error(result);
- }
- void open(const wchar_t *filename)
- {
- int result=sqlite3_open16(filename, &m_db);
- if(result!=SQLITE_OK)
- throw sqlite::error(result);
- }
- void close()
- {
- if(m_db)
- {
- sqlite3_close_v2(m_db);
- m_db=NULL;
- }
- }
+ database() : m_db(NULL) {}
+ ~database() { close(); }
+ database(const database &) = delete;
+ database(database &&src)
+ {
+ m_db = src.m_db;
+ src.m_db = NULL;
+ }
+ database &operator=(const database &) = delete;
+ database &operator=(database &&src)
+ {
+ if (this != &src)
+ {
+ close();
+ m_db = src.m_db;
+ src.m_db = NULL;
+ }
+ return *this;
+ }
- statement open_command(const char* query_text, size_t text_length)
- {
- statement stmt;
- stmt.open(handle(), query_text, text_length);
- return stmt;
- }
- statement open_command(const char* query_text)
- {
- return open_command(query_text, strlen(query_text));
- }
- statement open_command(const std::string& query_text)
- {
- return open_command(query_text.data(), query_text.length());
- }
+ void open(const char *filename, int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE)
+ {
+ int result = sqlite3_open_v2(filename, &m_db, flags, NULL);
+ if (result != SQLITE_OK)
+ throw sqlite::error(result);
+ }
+ void open(const wchar_t *filename)
+ {
+ int result = sqlite3_open16(filename, &m_db);
+ if (result != SQLITE_OK)
+ throw sqlite::error(result);
+ }
+ void close()
+ {
+ if (m_db)
+ {
+ sqlite3_close_v2(m_db);
+ m_db = NULL;
+ }
+ }
- void simple_execute(const char* lpszSql)
- {
- int result=sqlite3_exec(m_db, lpszSql, NULL, NULL, NULL);
- if(result!=SQLITE_OK)
- throw sqlite::error(result);
- }
+ statement open_command(const char *query_text, size_t text_length)
+ {
+ statement stmt;
+ stmt.open(handle(), query_text, text_length);
+ return stmt;
+ }
+ statement open_command(const char *query_text)
+ {
+ return open_command(query_text, strlen(query_text));
+ }
+ statement open_command(const std::string &query_text)
+ {
+ return open_command(query_text.data(), query_text.length());
+ }
- void begin_transaction()
- {
- simple_execute("BEGIN TRANSACTION");
- }
- void commit()
- {
- simple_execute("COMMIT TRANSACTION");
- }
- void rollback()
- {
- simple_execute("ROLLBACK TRANSACTION");
- }
+ void simple_execute(const char *lpszSql)
+ {
+ int result = sqlite3_exec(m_db, lpszSql, NULL, NULL, NULL);
+ if (result != SQLITE_OK)
+ throw sqlite::error(result);
+ }
- bool is_alive()
- {
+ void begin_transaction()
+ {
+ simple_execute("BEGIN TRANSACTION");
+ }
+ void commit()
+ {
+ simple_execute("COMMIT TRANSACTION");
+ }
+ void rollback()
+ {
+ simple_execute("ROLLBACK TRANSACTION");
+ }
+
+ bool is_alive()
+ {
#ifdef _WIN32
- return true;
+ return true;
#else
- int has_moved=0;
- int result=sqlite3_file_control(m_db, NULL, SQLITE_FCNTL_HAS_MOVED, &has_moved);
- if(result!=SQLITE_OK)
- throw sqlite::error(result);
- return has_moved==0;
+ int has_moved = 0;
+ int result = sqlite3_file_control(m_db, NULL, SQLITE_FCNTL_HAS_MOVED, &has_moved);
+ if (result != SQLITE_OK)
+ throw sqlite::error(result);
+ return has_moved == 0;
#endif //_WIN32
- }
- const char* errmsg() const { return sqlite3_errmsg(m_db); }
- int error() const { return sqlite3_errcode(m_db); }
- uint64_t insert_id() { return sqlite3_last_insert_rowid(m_db); }
- sqlite3* handle() { return m_db; }
-
-protected:
- sqlite3* m_db;
-};
-
-// stream for blob field
-
-class blobbuf : public std::streambuf
-{
-public:
- blobbuf()
- {
- init();
- }
- blobbuf(const blobbuf&) = delete;
- blobbuf(blobbuf&& src) : std::streambuf(std::move(src))
- {
- init();
- swap(src);
- }
- virtual ~blobbuf()
- {
- if(m_blob)
- {
- close();
- }
- }
-
- blobbuf& operator=(const blobbuf&) = delete;
- blobbuf& operator=(blobbuf&& src)
- {
- if(this!=&src)
- {
- reset_back();
- close();
- swap(src);
- }
- return *this;
- }
-
- void swap( blobbuf& other )
- {
- std::swap(m_blob, other.m_blob);
- std::swap(m_inbuf, other.m_inbuf);
- std::swap(m_outbuf, other.m_outbuf);
- std::swap(m_size, other.m_size);
- std::swap(m_inpos, other.m_inpos);
- std::swap(m_outpos, other.m_outpos);
-
- std::streambuf::swap(other);
- std::swap(m_back_char, other.m_back_char);
- if(eback() == &other.m_back_char)
- set_back();
- else
- reset_back();
-
- if(other.eback()==&m_back_char)
- other.set_back();
- else
- other.reset_back();
- }
-
- static void init_blob(database& db, const char* table, const char* column, int64_t row, int length)
- {
- statement stmt;
- std::ostringstream oss;
- oss<< "UPDATE " << table << " SET " << column << "=? WHERE rowid=?";
- stmt.open(db.handle(), oss.str().data());
- stmt.bind_zero_blob(0, length);
- stmt.bind_param(1, row);
- stmt.fetch();
- }
- static void init_blob(database& db, const std::string& table, const std::string& column, int64_t row, int length)
- {
- return init_blob(db, table.c_str(), column.c_str(), row, length);
- }
-
- bool is_open() const { return m_blob!=nullptr; }
-
- blobbuf* open(database& db, const char* table, const char* column, sqlite3_int64 row,
- std::ios_base::openmode mode, const char* dbname="main")
- {
- int flags=0;
- if(mode&std::ios_base::out) flags=1;
- if(sqlite3_blob_open(db.handle(), dbname, table, column, row, flags, &m_blob)==SQLITE_OK)
- {
- m_size=sqlite3_blob_bytes(m_blob)/sizeof(char);
- // prepare buffer
- size_t bufsize=std::min<size_t>(default_buffer_size, m_size);
- if(mode&std::ios_base::in)
- {
- m_inbuf.resize(bufsize);
- m_inpos=0;
- setg(m_inbuf.data(), m_inbuf.data(), m_inbuf.data());
}
- if(mode&std::ios_base::out)
+ const char *errmsg() const { return sqlite3_errmsg(m_db); }
+ int error() const { return sqlite3_errcode(m_db); }
+ uint64_t insert_id() { return sqlite3_last_insert_rowid(m_db); }
+ sqlite3 *handle() { return m_db; }
+
+ protected:
+ sqlite3 *m_db;
+ };
+
+ // stream for blob field
+
+ class blobbuf : public std::streambuf
+ {
+ public:
+ blobbuf()
{
- m_outbuf.resize(bufsize);
- m_outpos=0;
- setp(m_outbuf.data(), m_outbuf.data()+bufsize);
+ init();
}
- }
- return this;
- }
- blobbuf* open(database& db, const std::string& table, const std::string& column, sqlite3_int64 row,
- std::ios_base::openmode mode, const char* dbname="main")
- {
- return open(db, table.c_str(), column.c_str(), row, mode, dbname);
- }
-
- blobbuf* close()
- {
- if(m_blob==nullptr)
- return nullptr;
-
- overflow();
- sqlite3_blob_close(m_blob);
- init();
- return this;
- }
-
- std::streamoff size() const { return std::streamoff(m_size); }
-
- void flush()
- {
- if(m_blob)
- overflow();
- }
-
-protected:
- enum { default_buffer_size = 4096 };
-
- virtual pos_type seekoff( off_type off, std::ios_base::seekdir dir,
- std::ios_base::openmode which = std::ios_base::in | std::ios_base::out ) override
- {
- if(!is_open())
- return pos_type(off_type(-1));
-
- pos_type pos=0;
- if(which&std::ios_base::out)
- {
- pos=seekoff(m_outpos, off, dir);
- }
- else if(which&std::ios_base::in)
- {
- pos=seekoff(m_inpos, off, dir);
- }
- return seekpos(pos, which);
- }
-
- virtual pos_type seekpos( pos_type pos,
- std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) override
- {
- if(!is_open())
- return pos_type(off_type(-1));
- if(pos>=m_size)
- return pos_type(off_type(-1));
-
- if(which&std::ios_base::out)
- {
- if(pos<m_outpos || pos>=m_outpos+off_type(egptr()-pbase()))
+ blobbuf(const blobbuf &) = delete;
+ blobbuf(blobbuf &&src) : std::streambuf(std::move(src))
{
+ init();
+ swap(src);
+ }
+ virtual ~blobbuf()
+ {
+ if (m_blob)
+ {
+ close();
+ }
+ }
+
+ blobbuf &operator=(const blobbuf &) = delete;
+ blobbuf &operator=(blobbuf &&src)
+ {
+ if (this != &src)
+ {
+ reset_back();
+ close();
+ swap(src);
+ }
+ return *this;
+ }
+
+ void swap(blobbuf &other)
+ {
+ std::swap(m_blob, other.m_blob);
+ std::swap(m_inbuf, other.m_inbuf);
+ std::swap(m_outbuf, other.m_outbuf);
+ std::swap(m_size, other.m_size);
+ std::swap(m_inpos, other.m_inpos);
+ std::swap(m_outpos, other.m_outpos);
+
+ std::streambuf::swap(other);
+ std::swap(m_back_char, other.m_back_char);
+ if (eback() == &other.m_back_char)
+ set_back();
+ else
+ reset_back();
+
+ if (other.eback() == &m_back_char)
+ other.set_back();
+ else
+ other.reset_back();
+ }
+
+ static void init_blob(database &db, const char *table, const char *column, int64_t row, int length)
+ {
+ statement stmt;
+ std::ostringstream oss;
+ oss << "UPDATE " << table << " SET " << column << "=? WHERE rowid=?";
+ stmt.open(db.handle(), oss.str().data());
+ stmt.bind_zero_blob(0, length);
+ stmt.bind_param(1, row);
+ stmt.fetch();
+ }
+ static void init_blob(database &db, const std::string &table, const std::string &column, int64_t row, int length)
+ {
+ return init_blob(db, table.c_str(), column.c_str(), row, length);
+ }
+
+ bool is_open() const { return m_blob != nullptr; }
+
+ blobbuf *open(database &db, const char *table, const char *column, sqlite3_int64 row,
+ std::ios_base::openmode mode, const char *dbname = "main")
+ {
+ int flags = 0;
+ if (mode & std::ios_base::out)
+ flags = 1;
+ if (sqlite3_blob_open(db.handle(), dbname, table, column, row, flags, &m_blob) == SQLITE_OK)
+ {
+ m_size = sqlite3_blob_bytes(m_blob) / sizeof(char);
+ // prepare buffer
+ size_t bufsize = std::min<size_t>(default_buffer_size, m_size);
+ if (mode & std::ios_base::in)
+ {
+ m_inbuf.resize(bufsize);
+ m_inpos = 0;
+ setg(m_inbuf.data(), m_inbuf.data(), m_inbuf.data());
+ }
+ if (mode & std::ios_base::out)
+ {
+ m_outbuf.resize(bufsize);
+ m_outpos = 0;
+ setp(m_outbuf.data(), m_outbuf.data() + bufsize);
+ }
+ }
+ return this;
+ }
+ blobbuf *open(database &db, const std::string &table, const std::string &column, sqlite3_int64 row,
+ std::ios_base::openmode mode, const char *dbname = "main")
+ {
+ return open(db, table.c_str(), column.c_str(), row, mode, dbname);
+ }
+
+ blobbuf *close()
+ {
+ if (m_blob == nullptr)
+ return nullptr;
+
overflow();
- m_outpos=pos;
- setp(m_outbuf.data(), m_outbuf.data()+m_outbuf.size());
+ sqlite3_blob_close(m_blob);
+ init();
+ return this;
}
- else
+
+ std::streamoff size() const { return std::streamoff(m_size); }
+
+ void flush()
{
- pbump(off_type(pos-pabs()));
+ if (m_blob)
+ overflow();
}
- }
- else if(which&std::ios_base::in)
- {
- if(pos<m_inpos || pos>=m_inpos+off_type(epptr()-eback()))
+
+ protected:
+ enum
{
- m_inpos=pos;
- setg(m_inbuf.data(), m_inbuf.data(), m_inbuf.data());
- }
- else
+ default_buffer_size = 4096
+ };
+
+ virtual pos_type seekoff(off_type off, std::ios_base::seekdir dir,
+ std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) override
{
- gbump(off_type(pos-gabs()));
+ if (!is_open())
+ return pos_type(off_type(-1));
+
+ pos_type pos = 0;
+ if (which & std::ios_base::out)
+ {
+ pos = seekoff(m_outpos, off, dir);
+ }
+ else if (which & std::ios_base::in)
+ {
+ pos = seekoff(m_inpos, off, dir);
+ }
+ return seekpos(pos, which);
}
- }
- return pos;
- }
- virtual std::streamsize showmanyc() override
- {
- return m_size-pabs();
- }
-
- //reads characters from the associated input sequence to the get area
- virtual int_type underflow() override
- {
- if(!is_open())
- return traits_type::eof();
-
- if(pptr()>pbase())
- overflow();
-
- off_type count=egptr()-eback();
- pos_type next_pos=0;
- if(count==0 && eback()==m_inbuf.data())
- {
- setg(m_inbuf.data(), m_inbuf.data(), m_inbuf.data()+m_inbuf.size());
- count=m_inbuf.size();
- }
- else
- {
- next_pos=m_inpos+pos_type(count);
- }
- if(next_pos>=m_size)
- return traits_type::eof();
-
- count=std::min(count, m_size-next_pos);
- m_inpos = next_pos;
- if(sqlite3_blob_read(m_blob, eback(), count, m_inpos)!=SQLITE_OK)
- return traits_type::eof();
- setg(eback(), eback(), eback()+count);
- return traits_type::to_int_type(*gptr());
- }
-
- /*//reads characters from the associated input sequence to the get area and advances the next pointer
- virtual int_type uflow() override
- {
-
- }*/
-
- //writes characters to the associated output sequence from the put area
- virtual int_type overflow( int_type ch = traits_type::eof() ) override
- {
- if(!is_open())
- return traits_type::eof();
-
- if(pptr()!=pbase())
- {
- size_t count = pptr()-pbase();
- if(sqlite3_blob_write(m_blob, pbase(), count, m_outpos)!=SQLITE_OK)
- return traits_type::eof();
-
- auto intersection = interval_intersection(m_inpos, egptr()-eback(), m_outpos, epptr()-pbase());
- if(intersection.first!=intersection.second)
+ virtual pos_type seekpos(pos_type pos,
+ std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) override
{
- commit(intersection.first, intersection.second);
+ if (!is_open())
+ return pos_type(off_type(-1));
+ if (pos >= m_size)
+ return pos_type(off_type(-1));
+
+ if (which & std::ios_base::out)
+ {
+ if (pos < m_outpos || pos >= m_outpos + off_type(egptr() - pbase()))
+ {
+ overflow();
+ m_outpos = pos;
+ setp(m_outbuf.data(), m_outbuf.data() + m_outbuf.size());
+ }
+ else
+ {
+ pbump(off_type(pos - pabs()));
+ }
+ }
+ else if (which & std::ios_base::in)
+ {
+ if (pos < m_inpos || pos >= m_inpos + off_type(epptr() - eback()))
+ {
+ m_inpos = pos;
+ setg(m_inbuf.data(), m_inbuf.data(), m_inbuf.data());
+ }
+ else
+ {
+ gbump(off_type(pos - gabs()));
+ }
+ }
+ return pos;
}
- m_outpos+=count;
- setp(pbase(), epptr());
- }
- if(!traits_type::eq_int_type(ch, traits_type::eof()))
- {
- char_type c = traits_type::to_char_type(ch);
- if(m_outpos>=m_size)
- return traits_type::eof();
- if(sqlite3_blob_write(m_blob, &c, 1, m_outpos)!=SQLITE_OK)
- return traits_type::eof();
- auto intersection = interval_intersection(m_inpos, egptr()-eback(), m_outpos, 1);
- if(intersection.first!=intersection.second)
+ virtual std::streamsize showmanyc() override
{
- eback()[intersection.first-m_inpos]=c;
+ return m_size - pabs();
}
- m_outpos+=1;
-
- }
- return ch;
- }
- virtual int_type pbackfail( int_type c = traits_type::eof() ) override
- {
- if (gptr() == 0
- || gptr() <= eback()
- || (!traits_type::eq_int_type(traits_type::eof(), c)
- && !traits_type::eq(traits_type::to_char_type(c), gptr()[-1])))
+ // reads characters from the associated input sequence to the get area
+ virtual int_type underflow() override
+ {
+ if (!is_open())
+ return traits_type::eof();
+
+ if (pptr() > pbase())
+ overflow();
+
+ off_type count = egptr() - eback();
+ pos_type next_pos = 0;
+ if (count == 0 && eback() == m_inbuf.data())
+ {
+ setg(m_inbuf.data(), m_inbuf.data(), m_inbuf.data() + m_inbuf.size());
+ count = m_inbuf.size();
+ }
+ else
+ {
+ next_pos = m_inpos + pos_type(count);
+ }
+ if (next_pos >= m_size)
+ return traits_type::eof();
+
+ count = std::min(count, m_size - next_pos);
+ m_inpos = next_pos;
+ if (sqlite3_blob_read(m_blob, eback(), count, m_inpos) != SQLITE_OK)
+ return traits_type::eof();
+ setg(eback(), eback(), eback() + count);
+ return traits_type::to_int_type(*gptr());
+ }
+
+ /*//reads characters from the associated input sequence to the get area and advances the next pointer
+ virtual int_type uflow() override
+ {
+
+ }*/
+
+ // writes characters to the associated output sequence from the put area
+ virtual int_type overflow(int_type ch = traits_type::eof()) override
+ {
+ if (!is_open())
+ return traits_type::eof();
+
+ if (pptr() != pbase())
+ {
+ size_t count = pptr() - pbase();
+ if (sqlite3_blob_write(m_blob, pbase(), count, m_outpos) != SQLITE_OK)
+ return traits_type::eof();
+
+ auto intersection = interval_intersection(m_inpos, egptr() - eback(), m_outpos, epptr() - pbase());
+ if (intersection.first != intersection.second)
+ {
+ commit(intersection.first, intersection.second);
+ }
+
+ m_outpos += count;
+ setp(pbase(), epptr());
+ }
+ if (!traits_type::eq_int_type(ch, traits_type::eof()))
+ {
+ char_type c = traits_type::to_char_type(ch);
+ if (m_outpos >= m_size)
+ return traits_type::eof();
+ if (sqlite3_blob_write(m_blob, &c, 1, m_outpos) != SQLITE_OK)
+ return traits_type::eof();
+ auto intersection = interval_intersection(m_inpos, egptr() - eback(), m_outpos, 1);
+ if (intersection.first != intersection.second)
+ {
+ eback()[intersection.first - m_inpos] = c;
+ }
+ m_outpos += 1;
+ }
+ return ch;
+ }
+
+ virtual int_type pbackfail(int_type c = traits_type::eof()) override
+ {
+ if (gptr() == 0 || gptr() <= eback() || (!traits_type::eq_int_type(traits_type::eof(), c) && !traits_type::eq(traits_type::to_char_type(c), gptr()[-1])))
+ {
+ return (traits_type::eof()); // can't put back, fail
+ }
+ else
+ { // back up one position and store put-back character
+ gbump(-1);
+ if (!traits_type::eq_int_type(traits_type::eof(), c))
+ *gptr() = traits_type::to_char_type(c);
+ return (traits_type::not_eof(c));
+ }
+ }
+
+ private:
+ sqlite3_blob *m_blob;
+ std::vector<char> m_inbuf;
+ std::vector<char> m_outbuf;
+ pos_type m_size;
+ pos_type m_inpos; // position in the input sequence
+ pos_type m_outpos; // position in the output sequence
+
+ void init()
+ {
+ m_blob = nullptr;
+ m_size = 0;
+ m_inpos = m_outpos = 0;
+ m_set_eback = m_set_egptr = nullptr;
+ m_back_char = 0;
+ setg(nullptr, nullptr, nullptr);
+ setp(nullptr, nullptr);
+ }
+
+ off_type seekoff(off_type position, off_type off, std::ios_base::seekdir dir)
+ {
+ off_type result = 0;
+ switch (dir)
+ {
+ case std::ios_base::beg:
+ result = off;
+ break;
+ case std::ios_base::cur:
+ result = position + off;
+ break;
+ case std::ios_base::end:
+ result = m_size - off;
+ break;
+ }
+ if (result > m_size)
+ result = m_size;
+ return result;
+ }
+
+ void reset_back()
+ { // restore buffer after putback
+ if (this->eback() == &m_back_char)
+ this->setg(m_set_eback, m_set_eback, m_set_egptr);
+ }
+
+ void set_back()
+ { // set up putback area
+ if (this->eback() != &m_back_char)
+ { // save current get buffer
+ m_set_eback = this->eback();
+ m_set_egptr = this->egptr();
+ }
+ this->setg(&m_back_char, &m_back_char, &m_back_char + 1);
+ }
+
+ char_type *m_set_eback{nullptr}; // saves eback() during one-element putback
+ char_type *m_set_egptr{nullptr}; // saves egptr()
+ char_type m_back_char{0};
+
+ void move_data(blobbuf &other)
+ {
+ m_blob = other.m_blob;
+ other.m_blob = nullptr;
+ m_size = other.m_size;
+ other.m_size = 0;
+ m_inpos = other.m_inpos;
+ other.m_inpos = 0;
+ m_outpos = other.m_outpos;
+ other.m_outpos = 0;
+ }
+
+ static std::pair<pos_type, pos_type> interval_intersection(pos_type first1, pos_type last1, pos_type first2, pos_type last2)
+ {
+ if (first1 > first2)
+ {
+ std::swap(first1, first2);
+ std::swap(last1, last2);
+ }
+
+ if (first2 < last1)
+ return std::make_pair(first2, std::min(last1, last2));
+ else
+ return std::make_pair(0, 0);
+ }
+
+ static std::pair<pos_type, pos_type> interval_intersection(pos_type first1, off_type count1, pos_type first2, off_type count2)
+ {
+ return interval_intersection(first1, first1 + count1, first2, first2 + count2);
+ }
+
+ void commit(off_type first, off_type last)
+ {
+ char_type *src = pbase() + (first - m_outpos);
+ char_type *dest = eback() + (first - m_inpos);
+ memmove(dest, src, last - first);
+ }
+
+ pos_type gabs() const // absolute offset of input pointer in blob field
+ {
+ return m_inpos + off_type(gptr() - eback());
+ }
+
+ pos_type pabs() const // absolute offset of output pointer in blob field
+ {
+ return m_outpos + off_type(pptr() - pbase());
+ }
+ };
+
+ class iblobstream : public std::istream
{
- return (traits_type::eof()); // can't put back, fail
- }
- else
- { // back up one position and store put-back character
- gbump(-1);
- if (!traits_type::eq_int_type(traits_type::eof(), c))
- *gptr() = traits_type::to_char_type(c);
- return (traits_type::not_eof(c));
- }
- }
+ public:
+ iblobstream() : std::istream(&m_buffer) {}
+ iblobstream(database &db, const char *table, const char *column, sqlite3_int64 row,
+ std::ios_base::openmode mode = std::ios_base::in, const char *dbname = "main")
+ : std::istream(&m_buffer)
+ {
+ open(db, table, column, row, mode, dbname);
+ }
+ iblobstream(database &db, const std::string &table, const std::string &column, sqlite3_int64 row,
+ std::ios_base::openmode mode = std::ios_base::in, const char *dbname = "main")
+ : std::istream(&m_buffer)
+ {
+ open(db, table, column, row, mode, dbname);
+ }
+ iblobstream(const iblobstream &) = delete;
+ iblobstream(iblobstream &&src) : std::istream(&m_buffer), m_buffer(std::move(src.m_buffer)) {}
-private:
- sqlite3_blob* m_blob;
- std::vector<char> m_inbuf;
- std::vector<char> m_outbuf;
- pos_type m_size;
- pos_type m_inpos; //position in the input sequence
- pos_type m_outpos; //position in the output sequence
+ iblobstream &operator=(const iblobstream &) = delete;
+ iblobstream &operator=(iblobstream &&src)
+ {
+ m_buffer.operator=(std::move(src.m_buffer));
+ }
- void init()
- {
- m_blob=nullptr;
- m_size=0;
- m_inpos=m_outpos=0;
- m_set_eback=m_set_egptr=nullptr;
- m_back_char=0;
- setg(nullptr, nullptr, nullptr);
- setp(nullptr, nullptr);
- }
+ bool is_open() const { return m_buffer.is_open(); }
- off_type seekoff(off_type position, off_type off, std::ios_base::seekdir dir)
- {
- off_type result=0;
- switch(dir)
+ void open(database &db, const char *table, const char *column, sqlite3_int64 row,
+ std::ios_base::openmode mode = std::ios_base::in, const char *dbname = "main")
+ {
+ if (m_buffer.open(db, table, column, row, mode | std::ios_base::in, dbname) == nullptr)
+ this->setstate(std::ios_base::failbit);
+ else
+ this->clear();
+ }
+ void open(database &db, const std::string &table, const std::string &column, sqlite3_int64 row,
+ std::ios_base::openmode mode = std::ios_base::in, const char *dbname = "main")
+ {
+ open(db, table.c_str(), column.c_str(), row, mode, dbname);
+ }
+
+ void close()
+ {
+ if (m_buffer.close() == nullptr)
+ this->setstate(std::ios_base::failbit);
+ }
+
+ blobbuf *rdbuf() const
+ {
+ return const_cast<blobbuf *>(&m_buffer);
+ }
+
+ std::streamoff blob_size() const { return m_buffer.size(); }
+
+ private:
+ blobbuf m_buffer;
+ };
+
+ class oblobstream : public std::ostream
{
- case std::ios_base::beg:
- result=off;
- break;
- case std::ios_base::cur:
- result=position+off;
- break;
- case std::ios_base::end:
- result=m_size-off;
- break;
- }
- if(result>m_size)
- result=m_size;
- return result;
- }
+ public:
+ oblobstream() : std::ostream(&m_buffer) {}
+ oblobstream(database &db, const char *table, const char *column, sqlite3_int64 row,
+ std::ios_base::openmode mode = std::ios_base::in, const char *dbname = "main")
+ : std::ostream(&m_buffer)
+ {
+ open(db, table, column, row, mode, dbname);
+ }
+ oblobstream(database &db, const std::string &table, const std::string &column, sqlite3_int64 row,
+ std::ios_base::openmode mode = std::ios_base::in, const char *dbname = "main")
+ : std::ostream(&m_buffer)
+ {
+ open(db, table, column, row, mode, dbname);
+ }
+ oblobstream(const oblobstream &) = delete;
+ oblobstream(oblobstream &&src) : std::ostream(&m_buffer), m_buffer(std::move(src.m_buffer)) {}
- void reset_back()
- { // restore buffer after putback
- if (this->eback() == &m_back_char)
- this->setg(m_set_eback, m_set_eback, m_set_egptr);
- }
+ oblobstream &operator=(const oblobstream &) = delete;
+ oblobstream &operator=(oblobstream &&src)
+ {
+ m_buffer.operator=(std::move(src.m_buffer));
+ }
- void set_back()
- { // set up putback area
- if (this->eback() != &m_back_char)
- { // save current get buffer
- m_set_eback = this->eback();
- m_set_egptr = this->egptr();
- }
- this->setg(&m_back_char, &m_back_char, &m_back_char + 1);
- }
+ bool is_open() const { return m_buffer.is_open(); }
- char_type *m_set_eback { nullptr }; // saves eback() during one-element putback
- char_type *m_set_egptr { nullptr }; // saves egptr()
- char_type m_back_char { 0 };
+ void open(database &db, const char *table, const char *column, sqlite3_int64 row,
+ std::ios_base::openmode mode = std::ios_base::out, const char *dbname = "main")
+ {
+ if (m_buffer.open(db, table, column, row, mode | std::ios_base::out, dbname) == nullptr)
+ this->setstate(std::ios_base::failbit);
+ else
+ this->clear();
+ }
+ void open(database &db, const std::string &table, const std::string &column, sqlite3_int64 row,
+ std::ios_base::openmode mode = std::ios_base::out, const char *dbname = "main")
+ {
+ open(db, table.c_str(), column.c_str(), row, mode, dbname);
+ }
- void move_data(blobbuf& other)
- {
- m_blob=other.m_blob;
- other.m_blob=nullptr;
- m_size=other.m_size;
- other.m_size=0;
- m_inpos=other.m_inpos;
- other.m_inpos=0;
- m_outpos=other.m_outpos;
- other.m_outpos=0;
- }
+ void close()
+ {
+ if (m_buffer.close() == nullptr)
+ this->setstate(std::ios_base::failbit);
+ }
- static std::pair<pos_type, pos_type> interval_intersection(pos_type first1, pos_type last1, pos_type first2, pos_type last2)
- {
- if(first1>first2)
+ blobbuf *rdbuf() const
+ {
+ return const_cast<blobbuf *>(&m_buffer);
+ }
+
+ std::streamoff blob_size() const { return m_buffer.size(); }
+
+ private:
+ blobbuf m_buffer;
+ };
+
+ class blobstream : public std::iostream
{
- std::swap(first1, first2);
- std::swap(last1, last2);
+ public:
+ blobstream() : std::iostream(&m_buffer) {}
+ blobstream(database &db, const char *table, const char *column, sqlite3_int64 row,
+ std::ios_base::openmode mode = std::ios_base::in, const char *dbname = "main")
+ : std::iostream(&m_buffer)
+ {
+ open(db, table, column, row, mode, dbname);
+ }
+ blobstream(database &db, const std::string &table, const std::string &column, sqlite3_int64 row,
+ std::ios_base::openmode mode = std::ios_base::in, const char *dbname = "main")
+ : std::iostream(&m_buffer)
+ {
+ open(db, table, column, row, mode, dbname);
+ }
+ blobstream(const blobstream &) = delete;
+ blobstream(blobstream &&src) : std::iostream(&m_buffer), m_buffer(std::move(src.m_buffer)) {}
+
+ blobstream &operator=(const blobstream &) = delete;
+ blobstream &operator=(blobstream &&src)
+ {
+ m_buffer.operator=(std::move(src.m_buffer));
+ }
+
+ bool is_open() const { return m_buffer.is_open(); }
+
+ void open(database &db, const char *table, const char *column, sqlite3_int64 row,
+ std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out, const char *dbname = "main")
+ {
+ if (m_buffer.open(db, table, column, row, mode | std::ios_base::in | std::ios_base::out, dbname) == nullptr)
+ this->setstate(std::ios_base::failbit);
+ else
+ this->clear();
+ }
+ void open(database &db, const std::string &table, const std::string &column, sqlite3_int64 row,
+ std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out, const char *dbname = "main")
+ {
+ open(db, table.c_str(), column.c_str(), row, mode, dbname);
+ }
+
+ void close()
+ {
+ if (m_buffer.close() == nullptr)
+ this->setstate(std::ios_base::failbit);
+ }
+
+ blobbuf *rdbuf() const
+ {
+ return const_cast<blobbuf *>(&m_buffer);
+ }
+
+ std::streamoff blob_size() const { return m_buffer.size(); }
+
+ private:
+ blobbuf m_buffer;
+ };
+
+ typedef qtl::transaction<database> transaction;
+
+ template <typename Record>
+ using query_iterator = qtl::query_iterator<statement, Record>;
+
+ template <typename Record>
+ using query_result = qtl::query_result<statement, Record>;
+
+ template <typename Params>
+ inline statement &operator<<(statement &stmt, const Params ¶ms)
+ {
+ stmt.reset();
+ stmt.execute(params);
+ return stmt;
}
- if(first2<last1)
- return std::make_pair(first2, std::min(last1, last2));
- else
- return std::make_pair(0, 0);
+ template <>
+ inline const char *statement::get_text_value<char>(int col) const
+ {
+ return (const char *)sqlite3_column_text(m_stmt, col);
+ }
+ template <>
+ inline const wchar_t *statement::get_text_value<wchar_t>(int col) const
+ {
+ return (const wchar_t *)sqlite3_column_text16(m_stmt, col);
+ }
+
}
-
- static std::pair<pos_type, pos_type> interval_intersection(pos_type first1, off_type count1, pos_type first2, off_type count2)
- {
- return interval_intersection(first1, first1+count1, first2, first2+count2);
- }
-
- void commit(off_type first, off_type last)
- {
- char_type* src= pbase()+(first-m_outpos);
- char_type* dest = eback()+(first-m_inpos);
- memmove(dest, src, last-first);
- }
-
- pos_type gabs() const // absolute offset of input pointer in blob field
- {
- return m_inpos+off_type(gptr()-eback());
- }
-
- pos_type pabs() const // absolute offset of output pointer in blob field
- {
- return m_outpos+off_type(pptr()-pbase());
- }
-};
-
-class iblobstream : public std::istream
-{
-public:
- iblobstream() : std::istream(&m_buffer) { }
- iblobstream(database& db, const char* table, const char* column, sqlite3_int64 row,
- std::ios_base::openmode mode=std::ios_base::in, const char* dbname="main")
- : std::istream(&m_buffer)
- {
- open(db, table, column, row, mode, dbname);
- }
- iblobstream(database& db, const std::string& table, const std::string& column, sqlite3_int64 row,
- std::ios_base::openmode mode=std::ios_base::in, const char* dbname="main")
- : std::istream(&m_buffer)
- {
- open(db, table, column, row, mode, dbname);
- }
- iblobstream(const iblobstream&) = delete;
- iblobstream(iblobstream&& src) : std::istream(&m_buffer), m_buffer(std::move(src.m_buffer)) { }
-
- iblobstream& operator=(const iblobstream&) = delete;
- iblobstream& operator=(iblobstream&& src)
- {
- m_buffer.operator =(std::move(src.m_buffer));
- }
-
- bool is_open() const { return m_buffer.is_open(); }
-
- void open(database& db, const char* table, const char* column, sqlite3_int64 row,
- std::ios_base::openmode mode=std::ios_base::in, const char* dbname="main")
- {
- if(m_buffer.open(db, table, column, row, mode|std::ios_base::in, dbname)==nullptr)
- this->setstate(std::ios_base::failbit);
- else
- this->clear();
- }
- void open(database& db, const std::string& table, const std::string& column, sqlite3_int64 row,
- std::ios_base::openmode mode=std::ios_base::in, const char* dbname="main")
- {
- open(db, table.c_str(), column.c_str(), row, mode, dbname);
- }
-
- void close()
- {
- if(m_buffer.close()==nullptr)
- this->setstate(std::ios_base::failbit);
- }
-
- blobbuf* rdbuf() const
- {
- return const_cast<blobbuf*>(&m_buffer);
- }
-
- std::streamoff blob_size() const { return m_buffer.size(); }
-
-private:
- blobbuf m_buffer;
-};
-
-class oblobstream : public std::ostream
-{
-public:
- oblobstream() : std::ostream(&m_buffer) { }
- oblobstream(database& db, const char* table, const char* column, sqlite3_int64 row,
- std::ios_base::openmode mode=std::ios_base::in, const char* dbname="main")
- : std::ostream(&m_buffer)
- {
- open(db, table, column, row, mode, dbname);
- }
- oblobstream(database& db, const std::string& table, const std::string& column, sqlite3_int64 row,
- std::ios_base::openmode mode=std::ios_base::in, const char* dbname="main")
- : std::ostream(&m_buffer)
- {
- open(db, table, column, row, mode, dbname);
- }
- oblobstream(const oblobstream&) = delete;
- oblobstream(oblobstream&& src) : std::ostream(&m_buffer), m_buffer(std::move(src.m_buffer)) { }
-
- oblobstream& operator=(const oblobstream&) = delete;
- oblobstream& operator=(oblobstream&& src)
- {
- m_buffer.operator =(std::move(src.m_buffer));
- }
-
- bool is_open() const { return m_buffer.is_open(); }
-
- void open(database& db, const char* table, const char* column, sqlite3_int64 row,
- std::ios_base::openmode mode=std::ios_base::out, const char* dbname="main")
- {
- if(m_buffer.open(db, table, column, row, mode|std::ios_base::out, dbname)==nullptr)
- this->setstate(std::ios_base::failbit);
- else
- this->clear();
- }
- void open(database& db, const std::string& table, const std::string& column, sqlite3_int64 row,
- std::ios_base::openmode mode=std::ios_base::out, const char* dbname="main")
- {
- open(db, table.c_str(), column.c_str(), row, mode, dbname);
- }
-
- void close()
- {
- if(m_buffer.close()==nullptr)
- this->setstate(std::ios_base::failbit);
- }
-
- blobbuf* rdbuf() const
- {
- return const_cast<blobbuf*>(&m_buffer);
- }
-
- std::streamoff blob_size() const { return m_buffer.size(); }
-
-private:
- blobbuf m_buffer;
-};
-
-class blobstream : public std::iostream
-{
-public:
- blobstream() : std::iostream(&m_buffer) { }
- blobstream(database& db, const char* table, const char* column, sqlite3_int64 row,
- std::ios_base::openmode mode=std::ios_base::in, const char* dbname="main")
- : std::iostream(&m_buffer)
- {
- open(db, table, column, row, mode, dbname);
- }
- blobstream(database& db, const std::string& table, const std::string& column, sqlite3_int64 row,
- std::ios_base::openmode mode=std::ios_base::in, const char* dbname="main")
- : std::iostream(&m_buffer)
- {
- open(db, table, column, row, mode, dbname);
- }
- blobstream(const blobstream&) = delete;
- blobstream(blobstream&& src) : std::iostream(&m_buffer), m_buffer(std::move(src.m_buffer)) { }
-
- blobstream& operator=(const blobstream&) = delete;
- blobstream& operator=(blobstream&& src)
- {
- m_buffer.operator =(std::move(src.m_buffer));
- }
-
- bool is_open() const { return m_buffer.is_open(); }
-
- void open(database& db, const char* table, const char* column, sqlite3_int64 row,
- std::ios_base::openmode mode=std::ios_base::in|std::ios_base::out, const char* dbname="main")
- {
- if(m_buffer.open(db, table, column, row, mode|std::ios_base::in|std::ios_base::out, dbname)==nullptr)
- this->setstate(std::ios_base::failbit);
- else
- this->clear();
- }
- void open(database& db, const std::string& table, const std::string& column, sqlite3_int64 row,
- std::ios_base::openmode mode=std::ios_base::in|std::ios_base::out, const char* dbname="main")
- {
- open(db, table.c_str(), column.c_str(), row, mode, dbname);
- }
-
- void close()
- {
- if(m_buffer.close()==nullptr)
- this->setstate(std::ios_base::failbit);
- }
-
- blobbuf* rdbuf() const
- {
- return const_cast<blobbuf*>(&m_buffer);
- }
-
- std::streamoff blob_size() const { return m_buffer.size(); }
-
-private:
- blobbuf m_buffer;
-};
-
-
-typedef qtl::transaction<database> transaction;
-
-template<typename Record>
-using query_iterator = qtl::query_iterator<statement, Record>;
-
-template<typename Record>
-using query_result = qtl::query_result<statement, Record>;
-
-template<typename Params>
-inline statement& operator<<(statement& stmt, const Params& params)
-{
- stmt.reset();
- stmt.execute(params);
- return stmt;
-}
-
-template<>
-inline const char* statement::get_text_value<char>(int col) const
-{
- return (const char*)sqlite3_column_text(m_stmt, col);
-}
-template<>
-inline const wchar_t* statement::get_text_value<wchar_t>(int col) const
-{
- return (const wchar_t*)sqlite3_column_text16(m_stmt, col);
-}
-
-}
}
diff --git a/include/qtl_sqlite_pool.hpp b/include/qtl_sqlite_pool.hpp
index 39ada04..e027bbb 100644
--- a/include/qtl_sqlite_pool.hpp
+++ b/include/qtl_sqlite_pool.hpp
@@ -7,37 +7,36 @@
namespace qtl
{
-namespace sqlite
-{
-
-class database_pool : public qtl::database_pool<database>
-{
-public:
- database_pool() : m_flags(SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE) { }
- virtual database* new_database() throw() override
+ namespace sqlite
{
- database* db=NULL;
- try
+
+ class database_pool : public qtl::database_pool<database>
{
- db=new database;
- db->open(m_filename.data(), m_flags);
- }
- catch (error& e)
- {
- delete db;
- db=NULL;
- }
- return db;
+ public:
+ database_pool() : m_flags(SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE) {}
+ virtual database *new_database() throw() override
+ {
+ database *db = NULL;
+ try
+ {
+ db = new database;
+ db->open(m_filename.data(), m_flags);
+ }
+ catch (error &e)
+ {
+ delete db;
+ db = NULL;
+ }
+ return db;
+ }
+
+ protected:
+ std::string m_filename;
+ int m_flags;
+ };
+
}
-
-protected:
- std::string m_filename;
- int m_flags;
-};
-
-}
}
#endif //_QTL_SQLITE_POOL_H_
-
--
Gitblit v1.9.3