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 &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
+								{
 			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 &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_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 &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)
+								{
 			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 &params)
+		{
+			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 &params)
+		{
+			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 &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
+								{
 			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 &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 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 &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 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 &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
+								{
 			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 &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)...);
+		}
 
-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 &param)
+	{
+		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 &param)
+	{
+		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 &param)
+	{
+		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> &param)
+	{
+		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...> &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));
+			}
 
-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...> &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...>
 		{
-			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...> &params) const
+			{
+			}
+			void operator()(std::tuple<Types...> &&params) 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 &param) 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...> &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:
-		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 &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)))
+			{
+				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 &params, 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 &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; }
+		};
+		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 &params)
 	{
-		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 &params, 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, &param](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, &param](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 &param)
+			{
+				m_binders[index].bind(nullptr, 0, MYSQL_TYPE_LONG_BLOB);
+				m_binderAddins[index].m_after_fetch = [this, index, &param](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 &param)
+			{
+				m_binders[index].bind(nullptr, 0, MYSQL_TYPE_LONG_BLOB);
+				m_binderAddins[index].m_after_fetch = [this, index, &param](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, 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([&params](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 &params)
+			{
+				execute_custom([&params](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 &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)
+						{
+							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 &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;
+		}
+
 	}
-
-	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, &param](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 &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, &param](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 &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)
+					{
+						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 &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();
+				};
+			}
 
-	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 &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();
+				};
 			}
-			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 &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);
-			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 &parameters);
+			std::string create_connection_text(const connection_parameters &parameters);
+		};
+
+		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 &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);
+				}
+
+				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 &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;
+				}
+				++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();
+		}
+
+		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 &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
 				{
-					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 &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++)
+					{
+						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> &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 (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 &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);
 
-			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> &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;
+				}
 
-		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 &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())
+					{
+						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 &params)
+		{
+			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