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_odbc.hpp | 3479 ++++++++++++++++++++++++++++++-----------------------------
 1 files changed, 1,755 insertions(+), 1,724 deletions(-)

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
 

--
Gitblit v1.9.3