Ferenc Szontágh
2024-07-01 abf49b44cc47f39d6cceb83866f915bc03b7d900
include/qtl_asio.hpp
@@ -4,8 +4,8 @@
#include "qtl_async.hpp"
#include <asio/version.hpp>
#define ASIO_STANDALONE
#if defined(_MSC_VER) && _WIN32_WINNT<0x0600
#define ASIO_ENABLE_CANCELIO 1
#if defined(_MSC_VER) && _WIN32_WINNT < 0x0600
#define ASIO_ENABLE_CANCELIO 1
#endif
#if ASIO_VERSION < 101200
#include <asio/io_service.hpp>
@@ -18,67 +18,68 @@
#include <asio/steady_timer.hpp>
#if ASIO_VERSION < 100000
#error The asio version required by QTL is at least 10.0
#error The asio version required by QTL is at least 10.0
#endif
namespace qtl
{
namespace NS_ASIO = ::asio;
   namespace NS_ASIO = ::asio;
namespace asio
{
   namespace asio
   {
class service
{
public:
      class service
      {
      public:
#if ASIO_VERSION < 101200
   typedef NS_ASIO::io_service service_type;
         typedef NS_ASIO::io_service service_type;
#else
   typedef NS_ASIO::io_context service_type;
         typedef NS_ASIO::io_context service_type;
#endif // ASIO_VERSION
   service() NOEXCEPT { }
   explicit service(int concurrency_hint) : _service(concurrency_hint) { }
         service() NOEXCEPT {}
         explicit service(int concurrency_hint) : _service(concurrency_hint) {}
   void reset()
   {
      _service.reset();
   }
   void run()
   {
      _service.run();
   }
   void stop()
   {
      _service.stop();
   }
   service_type& context() NOEXCEPT { return _service; }
private:
   class event_item : public qtl::event
   {
   public:
      event_item(service& service, qtl::socket_type fd)
         : _service(service), _strand(service.context()), _socket(service.context(), NS_ASIO::ip::tcp::v4(), fd), _timer(service.context()), _busying(false)
      {
      }
      NS_ASIO::ip::tcp::socket& next_layer() { return _socket; }
   public: // qtl::event
      virtual void set_io_handler(int flags, long timeout, std::function<void(int)>&& handler) override
      {
         if (flags&qtl::event::ef_read)
         void reset()
         {
            _service.reset();
         }
         void run()
         {
            _service.run();
         }
         void stop()
         {
            _service.stop();
         }
         service_type &context() NOEXCEPT { return _service; }
      private:
         class event_item : public qtl::event
         {
         public:
            event_item(service &service, qtl::socket_type fd)
               : _service(service), _strand(service.context()), _socket(service.context(), NS_ASIO::ip::tcp::v4(), fd), _timer(service.context()), _busying(false)
            {
            }
            NS_ASIO::ip::tcp::socket &next_layer() { return _socket; }
         public: // qtl::event
            virtual void set_io_handler(int flags, long timeout, std::function<void(int)> &&handler) override
            {
               if (flags & qtl::event::ef_read)
               {
#if ASIO_VERSION < 101200
            _socket.async_read_some(NS_ASIO::null_buffers(), _strand.wrap([this, handler](const NS_ASIO::error_code& ec, size_t bytes_transferred) {
                  _socket.async_read_some(NS_ASIO::null_buffers(), _strand.wrap([this, handler](const NS_ASIO::error_code &ec, size_t bytes_transferred)
                                                                 {
#else
            _socket.async_wait(NS_ASIO::socket_base::wait_read, _strand.wrap([this, handler](const NS_ASIO::error_code& ec) {
                  _socket.async_wait(NS_ASIO::socket_base::wait_read, _strand.wrap([this, handler](const NS_ASIO::error_code &ec)
                                                                   {
#endif // ASIO_VERSION
               if (!ec)
                  handler(qtl::event::ef_read);
@@ -87,17 +88,18 @@
               else
                  handler(qtl::event::ef_exception);
               _busying = false;
               _timer.cancel();
            }));
            _busying = true;
         }
         if (flags&qtl::event::ef_write)
         {
               _timer.cancel(); }));
                  _busying = true;
               }
               if (flags & qtl::event::ef_write)
               {
#if ASIO_VERSION < 101200
            _socket.async_write_some(NS_ASIO::null_buffers(), _strand.wrap([this, handler](const NS_ASIO::error_code& ec, size_t bytes_transferred) {
                  _socket.async_write_some(NS_ASIO::null_buffers(), _strand.wrap([this, handler](const NS_ASIO::error_code &ec, size_t bytes_transferred)
                                                                  {
#else
            _socket.async_wait(NS_ASIO::socket_base::wait_write, _strand.wrap([this, handler](const NS_ASIO::error_code& ec) {
#endif //ASIO_VERSION
                  _socket.async_wait(NS_ASIO::socket_base::wait_write, _strand.wrap([this, handler](const NS_ASIO::error_code &ec)
                                                                    {
#endif // ASIO_VERSION
               if (!ec)
                  handler(qtl::event::ef_write);
               else if (ec == NS_ASIO::error::make_error_code(NS_ASIO::error::operation_aborted))
@@ -105,292 +107,315 @@
               else
                  handler(qtl::event::ef_exception);
               _timer.cancel();
               _busying = false;
            }));
            _busying = true;
         }
         if (timeout > 0)
         {
               _busying = false; }));
                  _busying = true;
               }
               if (timeout > 0)
               {
#if ASIO_VERSION < 101200
            _timer.expires_from_now(std::chrono::seconds(timeout));
                  _timer.expires_from_now(std::chrono::seconds(timeout));
#else
            _timer.expires_after(NS_ASIO::chrono::seconds(timeout));
                  _timer.expires_after(NS_ASIO::chrono::seconds(timeout));
#endif // ASIO_VERSION
            _timer.async_wait(_strand.wrap([this, handler](NS_ASIO::error_code ec) {
                  _timer.async_wait(_strand.wrap([this, handler](NS_ASIO::error_code ec)
                                          {
               if (!ec)
               {
                  _socket.cancel(ec);
               } }));
               }
            }));
            }
            virtual void remove() override
            {
               if (_busying)
                  return;
#if ASIO_VERSION >= 101200 && (!defined(_WIN32) || _WIN32_WINNT >= 0x0603)
               _socket.release();
#endif // Windows 8.1
               _service.remove(this);
            }
            virtual bool is_busying() override
            {
               return _busying;
            }
         private:
            service &_service;
            service_type::strand _strand;
            NS_ASIO::ip::tcp::socket _socket;
            NS_ASIO::steady_timer _timer;
            bool _busying;
         };
      public:
         template <typename Connection>
         event_item *add(Connection *connection)
         {
            event_item *item = new event_item(*this, connection->socket());
            std::lock_guard<std::mutex> lock(_mutex);
            _events.push_back(std::unique_ptr<event_item>(item));
            return item;
         }
      }
      virtual void remove() override
      {
         if (_busying) return;
#if ASIO_VERSION >= 101200 && (!defined(_WIN32) || _WIN32_WINNT >= 0x0603 )
         _socket.release();
#endif //Windows 8.1
         _service.remove(this);
      }
      virtual bool is_busying() override
      {
         return _busying;
      }
      private:
         service_type _service;
         std::mutex _mutex;
         std::vector<std::unique_ptr<event_item>> _events;
   private:
      service& _service;
      service_type::strand _strand;
      NS_ASIO::ip::tcp::socket _socket;
      NS_ASIO::steady_timer _timer;
      bool _busying;
   };
public:
   template<typename Connection>
   event_item* add(Connection* connection)
   {
      event_item* item = new event_item(*this, connection->socket());
      std::lock_guard<std::mutex> lock(_mutex);
      _events.push_back(std::unique_ptr<event_item>(item));
      return item;
   }
private:
   service_type _service;
   std::mutex _mutex;
   std::vector<std::unique_ptr<event_item>> _events;
   void remove(event_item* item)
   {
      std::lock_guard<std::mutex> lock(_mutex);
      auto it = std::find_if(_events.begin(), _events.end(), [item](std::unique_ptr<event_item>& v) {
         return item==v.get();
      });
      if (it != _events.end()) _events.erase(it);
   }
};
         void remove(event_item *item)
         {
            std::lock_guard<std::mutex> lock(_mutex);
            auto it = std::find_if(_events.begin(), _events.end(), [item](std::unique_ptr<event_item> &v)
                              { return item == v.get(); });
            if (it != _events.end())
               _events.erase(it);
         }
      };
#if ASIO_VERSION < 101200
template <typename Handler, typename Signature>
using async_init_type  = NS_ASIO::detail::async_result_init<Handler, Signature>;
      template <typename Handler, typename Signature>
      using async_init_type = NS_ASIO::detail::async_result_init<Handler, Signature>;
template <typename Handler, typename Signature>
inline typename NS_ASIO::handler_type<Handler, Signature>::type
get_async_handler(async_init_type<Handler, Signature>& init)
{
   return init.handler;
}
      template <typename Handler, typename Signature>
      inline typename NS_ASIO::handler_type<Handler, Signature>::type
      get_async_handler(async_init_type<Handler, Signature> &init)
      {
         return init.handler;
      }
#else
template <typename Handler, typename Signature>
using async_init_type = NS_ASIO::async_completion<Handler, Signature>;
      template <typename Handler, typename Signature>
      using async_init_type = NS_ASIO::async_completion<Handler, Signature>;
template <typename Handler, typename Signature>
inline typename async_init_type<Handler, Signature>::completion_handler_type
get_async_handler(async_init_type<Handler, Signature>& init)
{
   return init.completion_handler;
}
      template <typename Handler, typename Signature>
      inline typename async_init_type<Handler, Signature>::completion_handler_type
      get_async_handler(async_init_type<Handler, Signature> &init)
      {
         return init.completion_handler;
      }
#endif // ASIO_VERSION
template<typename Connection, typename OpenHandler, typename... Args>
inline ASIO_INITFN_RESULT_TYPE(OpenHandler, void(typename Connection::exception_type))
async_open(service& service, Connection& db, OpenHandler&& handler, Args&&... args)
{
      template <typename Connection, typename OpenHandler, typename... Args>
      inline ASIO_INITFN_RESULT_TYPE(OpenHandler, void(typename Connection::exception_type))
         async_open(service &service, Connection &db, OpenHandler &&handler, Args &&...args)
      {
#if ASIO_VERSION < 101200
   async_init_type<OpenHandler,
      void(typename Connection::exception_type)> init(std::forward<OpenHandler>(handler));
         async_init_type<OpenHandler,
                     void(typename Connection::exception_type)>
            init(std::forward<OpenHandler>(handler));
#else
   async_init_type<OpenHandler,
      void(typename Connection::exception_type)> init(handler);
         async_init_type<OpenHandler,
                     void(typename Connection::exception_type)>
            init(handler);
#endif
   db.open(service, get_async_handler(init), std::forward<Args>(args)...);
   return init.result.get();
}
         db.open(service, get_async_handler(init), std::forward<Args>(args)...);
         return init.result.get();
      }
template<typename Connection, typename CloseHandler, typename... Args>
inline ASIO_INITFN_RESULT_TYPE(CloseHandler, void())
async_close(Connection& db, CloseHandler&& handler, Args&&... args)
{
      template <typename Connection, typename CloseHandler, typename... Args>
      inline ASIO_INITFN_RESULT_TYPE(CloseHandler, void())
         async_close(Connection &db, CloseHandler &&handler, Args &&...args)
      {
#if ASIO_VERSION < 101200
   async_init_type<CloseHandler,
      void()> init(std::forward<CloseHandler>(std::forward<CloseHandler>(handler)));
         async_init_type<CloseHandler,
                     void()>
            init(std::forward<CloseHandler>(std::forward<CloseHandler>(handler)));
#else
   async_init_type<CloseHandler,
      void()> init(std::forward<CloseHandler>(handler));
         async_init_type<CloseHandler,
                     void()>
            init(std::forward<CloseHandler>(handler));
#endif
   db.close(get_async_handler(init), std::forward<Args>(args)...);
   return init.result.get();
}
         db.close(get_async_handler(init), std::forward<Args>(args)...);
         return init.result.get();
      }
template<typename Connection, typename ExecuteHandler, typename... Args>
inline ASIO_INITFN_RESULT_TYPE(ExecuteHandler, void(typename Connection::exception_type, uint64_t))
async_execute(Connection& db, ExecuteHandler&& handler, Args&&... args)
{
      template <typename Connection, typename ExecuteHandler, typename... Args>
      inline ASIO_INITFN_RESULT_TYPE(ExecuteHandler, void(typename Connection::exception_type, uint64_t))
         async_execute(Connection &db, ExecuteHandler &&handler, Args &&...args)
      {
#if ASIO_VERSION < 101200
   async_init_type<ExecuteHandler,
      void(typename Connection::exception_type, uint64_t)> init(std::forward<ExecuteHandler>(handler));
         async_init_type<ExecuteHandler,
                     void(typename Connection::exception_type, uint64_t)>
            init(std::forward<ExecuteHandler>(handler));
#else
   async_init_type<ExecuteHandler,
      void(typename Connection::exception_type, uint64_t)> init(handler);
         async_init_type<ExecuteHandler,
                     void(typename Connection::exception_type, uint64_t)>
            init(handler);
#endif
   db.execute(get_async_handler(init), std::forward<Args>(args)...);
   return init.result.get();
}
         db.execute(get_async_handler(init), std::forward<Args>(args)...);
         return init.result.get();
      }
template<typename Connection, typename ExecuteHandler, typename... Args>
inline ASIO_INITFN_RESULT_TYPE(ExecuteHandler, void(typename Connection::exception_type, uint64_t))
async_execute_direct(Connection& db, ExecuteHandler&& handler, Args&&... args)
{
      template <typename Connection, typename ExecuteHandler, typename... Args>
      inline ASIO_INITFN_RESULT_TYPE(ExecuteHandler, void(typename Connection::exception_type, uint64_t))
         async_execute_direct(Connection &db, ExecuteHandler &&handler, Args &&...args)
      {
#if ASIO_VERSION < 101200
   async_init_type<ExecuteHandler,
      void(typename Connection::exception_type, uint64_t)> init(std::forward<ExecuteHandler>(handler));
         async_init_type<ExecuteHandler,
                     void(typename Connection::exception_type, uint64_t)>
            init(std::forward<ExecuteHandler>(handler));
#else
   async_init_type<ExecuteHandler,
      void(typename Connection::exception_type, uint64_t)> init(handler);
         async_init_type<ExecuteHandler,
                     void(typename Connection::exception_type, uint64_t)>
            init(handler);
#endif
   db.execute_direct(get_async_handler(init), std::forward<Args>(args)...);
   return init.result.get();
}
         db.execute_direct(get_async_handler(init), std::forward<Args>(args)...);
         return init.result.get();
      }
template<typename Connection, typename ExecuteHandler, typename... Args>
inline ASIO_INITFN_RESULT_TYPE(ExecuteHandler, void(typename Connection::exception_type, uint64_t))
 async_insert(Connection& db, ExecuteHandler&& handler, Args&&... args)
{
      template <typename Connection, typename ExecuteHandler, typename... Args>
      inline ASIO_INITFN_RESULT_TYPE(ExecuteHandler, void(typename Connection::exception_type, uint64_t))
         async_insert(Connection &db, ExecuteHandler &&handler, Args &&...args)
      {
#if ASIO_VERSION < 101200
   async_init_type<ExecuteHandler,
      void(typename Connection::exception_type, uint64_t)> init(std::forward<ExecuteHandler>(handler));
         async_init_type<ExecuteHandler,
                     void(typename Connection::exception_type, uint64_t)>
            init(std::forward<ExecuteHandler>(handler));
#else
   async_init_type<ExecuteHandler,
      void(typename Connection::exception_type, uint64_t)> init(handler);
         async_init_type<ExecuteHandler,
                     void(typename Connection::exception_type, uint64_t)>
            init(handler);
#endif
   db.insert(get_async_handler(init), std::forward<Args>(args)...);
   return init.result.get();
}
         db.insert(get_async_handler(init), std::forward<Args>(args)...);
         return init.result.get();
      }
template<typename Connection, typename ExecuteHandler, typename... Args>
inline ASIO_INITFN_RESULT_TYPE(ExecuteHandler, void(typename Connection::exception_type, uint64_t))
 async_insert_direct(Connection& db, ExecuteHandler&& handler, Args&&... args)
{
      template <typename Connection, typename ExecuteHandler, typename... Args>
      inline ASIO_INITFN_RESULT_TYPE(ExecuteHandler, void(typename Connection::exception_type, uint64_t))
         async_insert_direct(Connection &db, ExecuteHandler &&handler, Args &&...args)
      {
#if ASIO_VERSION < 101200
   async_init_type<ExecuteHandler,
      void(typename Connection::exception_type, uint64_t)> init(std::forward<ExecuteHandler>(handler));
         async_init_type<ExecuteHandler,
                     void(typename Connection::exception_type, uint64_t)>
            init(std::forward<ExecuteHandler>(handler));
#else
   async_init_type<ExecuteHandler,
      void(typename Connection::exception_type, uint64_t)> init(handler);
         async_init_type<ExecuteHandler,
                     void(typename Connection::exception_type, uint64_t)>
            init(handler);
#endif
   db.insert_direct(get_async_handler(init), std::forward<Args>(args)...);
   return init.result.get();
}
         db.insert_direct(get_async_handler(init), std::forward<Args>(args)...);
         return init.result.get();
      }
template<typename Connection, typename FinishHandler, typename... Args>
inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
 async_query(Connection& db, FinishHandler&& handler, Args&&... args)
{
      template <typename Connection, typename FinishHandler, typename... Args>
      inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
         async_query(Connection &db, FinishHandler &&handler, Args &&...args)
      {
#if ASIO_VERSION < 101200
   async_init_type<FinishHandler,
      void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler));
         async_init_type<FinishHandler,
                     void(typename Connection::exception_type)>
            init(std::forward<FinishHandler>(handler));
#else
   async_init_type<FinishHandler,
      void(typename Connection::exception_type)> init(handler);
         async_init_type<FinishHandler,
                     void(typename Connection::exception_type)>
            init(handler);
#endif
   db.query(std::forward<Args>(args)..., get_async_handler(init));
   return init.result.get();
}
         db.query(std::forward<Args>(args)..., get_async_handler(init));
         return init.result.get();
      }
template<typename Connection, typename FinishHandler, typename... Args>
inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
async_query_explicit(Connection& db, FinishHandler&& handler, Args&&... args)
{
      template <typename Connection, typename FinishHandler, typename... Args>
      inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
         async_query_explicit(Connection &db, FinishHandler &&handler, Args &&...args)
      {
#if ASIO_VERSION < 101200
   async_init_type<FinishHandler,
      void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler));
         async_init_type<FinishHandler,
                     void(typename Connection::exception_type)>
            init(std::forward<FinishHandler>(handler));
#else
   async_init_type<FinishHandler,
      void(typename Connection::exception_type)> init(handler);
         async_init_type<FinishHandler,
                     void(typename Connection::exception_type)>
            init(handler);
#endif
   db.query_explicit(std::forward<Args>(args)..., get_async_handler(init));
   return init.result.get();
}
         db.query_explicit(std::forward<Args>(args)..., get_async_handler(init));
         return init.result.get();
      }
template<typename Connection, typename A1, typename A2, typename FinishHandler, typename... RowHandlers>
inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
async_query_multi_with_params(Connection& db, A1&& a1, A2&& a2, FinishHandler&& handler, RowHandlers&&... row_handlers)
{
      template <typename Connection, typename A1, typename A2, typename FinishHandler, typename... RowHandlers>
      inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
         async_query_multi_with_params(Connection &db, A1 &&a1, A2 &&a2, FinishHandler &&handler, RowHandlers &&...row_handlers)
      {
#if ASIO_VERSION < 101200
   async_init_type<FinishHandler,
      void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler));
         async_init_type<FinishHandler,
                     void(typename Connection::exception_type)>
            init(std::forward<FinishHandler>(handler));
#else
   async_init_type<FinishHandler,
      void(typename Connection::exception_type)> init(handler);
         async_init_type<FinishHandler,
                     void(typename Connection::exception_type)>
            init(handler);
#endif
   db.query_multi_with_params(std::forward<A1>(a1), std::forward<A2>(a2), get_async_handler(init), std::forward<RowHandlers>(row_handlers)...);
   return init.result.get();
}
         db.query_multi_with_params(std::forward<A1>(a1), std::forward<A2>(a2), get_async_handler(init), std::forward<RowHandlers>(row_handlers)...);
         return init.result.get();
      }
template<typename Connection, typename A1, typename FinishHandler, typename... RowHandlers>
inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
async_query_multi_with_params(Connection& db, A1&& a1, FinishHandler&& handler, RowHandlers&&... row_handlers)
{
      template <typename Connection, typename A1, typename FinishHandler, typename... RowHandlers>
      inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
         async_query_multi_with_params(Connection &db, A1 &&a1, FinishHandler &&handler, RowHandlers &&...row_handlers)
      {
#if ASIO_VERSION < 101200
   async_init_type<FinishHandler,
      void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler));
         async_init_type<FinishHandler,
                     void(typename Connection::exception_type)>
            init(std::forward<FinishHandler>(handler));
#else
   async_init_type<FinishHandler,
      void(typename Connection::exception_type)> init(handler);
         async_init_type<FinishHandler,
                     void(typename Connection::exception_type)>
            init(handler);
#endif
   db.query_multi_with_params(std::forward<A1>(a1), get_async_handler(init), std::forward<RowHandlers>(row_handlers)...);
   return init.result.get();
}
         db.query_multi_with_params(std::forward<A1>(a1), get_async_handler(init), std::forward<RowHandlers>(row_handlers)...);
         return init.result.get();
      }
template<typename Connection, typename A1, typename A2, typename FinishHandler, typename... RowHandlers>
inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
async_query_multi(Connection& db, A1&& a1, A2&& a2, FinishHandler&& handler, RowHandlers&&... row_handlers)
{
      template <typename Connection, typename A1, typename A2, typename FinishHandler, typename... RowHandlers>
      inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
         async_query_multi(Connection &db, A1 &&a1, A2 &&a2, FinishHandler &&handler, RowHandlers &&...row_handlers)
      {
#if ASIO_VERSION < 101200
   async_init_type<FinishHandler,
      void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler));
         async_init_type<FinishHandler,
                     void(typename Connection::exception_type)>
            init(std::forward<FinishHandler>(handler));
#else
   async_init_type<FinishHandler,
      void(typename Connection::exception_type)> init(handler);
         async_init_type<FinishHandler,
                     void(typename Connection::exception_type)>
            init(handler);
#endif
   db.query_multi(std::forward<A1>(a1), std::forward<A2>(a2), get_async_handler(init), std::forward<RowHandlers>(row_handlers)...);
   return init.result.get();
}
         db.query_multi(std::forward<A1>(a1), std::forward<A2>(a2), get_async_handler(init), std::forward<RowHandlers>(row_handlers)...);
         return init.result.get();
      }
template<typename Connection, typename A1, typename FinishHandler, typename... RowHandlers>
inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
async_query_multi(Connection& db, A1&& a1, FinishHandler&& handler, RowHandlers&&... row_handlers)
{
      template <typename Connection, typename A1, typename FinishHandler, typename... RowHandlers>
      inline ASIO_INITFN_RESULT_TYPE(FinishHandler, void(typename Connection::exception_type))
         async_query_multi(Connection &db, A1 &&a1, FinishHandler &&handler, RowHandlers &&...row_handlers)
      {
#if ASIO_VERSION < 101200
   async_init_type<FinishHandler,
      void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler));
         async_init_type<FinishHandler,
                     void(typename Connection::exception_type)>
            init(std::forward<FinishHandler>(handler));
#else
   async_init_type<FinishHandler,
      void(typename Connection::exception_type)> init(handler);
         async_init_type<FinishHandler,
                     void(typename Connection::exception_type)>
            init(handler);
#endif
   db.query_multi(std::forward<A1>(a1), get_async_handler(init), std::forward<RowHandlers>(row_handlers)...);
   return init.result.get();
}
         db.query_multi(std::forward<A1>(a1), get_async_handler(init), std::forward<RowHandlers>(row_handlers)...);
         return init.result.get();
      }
}
   }
}