| | |
| | | static inline auto apply_tuple(F&& f, T&& t, A&&... a) |
| | | -> decltype(apply<N-1>::apply_tuple( |
| | | std::forward<F>(f), std::forward<T>(t), |
| | | std::get<N-1>(std::forward<T>(t)), std::forward<A>(a)... |
| | | )) |
| | | std::get<N - 1>(std::forward<T>(t)), std::forward<A>(a)...)) |
| | | { |
| | | return apply<N-1>::apply_tuple(std::forward<F>(f), std::forward<T>(t), |
| | | std::get<N-1>(std::forward<T>(t)), std::forward<A>(a)... |
| | | ); |
| | | std::get<N - 1>(std::forward<T>(t)), std::forward<A>(a)...); |
| | | } |
| | | }; |
| | | |
| | |
| | | template<typename F, typename T> |
| | | inline auto apply_tuple(F&& f, T&& t) |
| | | -> decltype(detail::apply< std::tuple_size< |
| | | typename std::decay<T>::type |
| | | >::value>::apply_tuple(std::forward<F>(f), std::forward<T>(t))) |
| | | typename std::decay<T>::type>::value>::apply_tuple(std::forward<F>(f), std::forward<T>(t))) |
| | | { |
| | | return detail::apply< std::tuple_size< |
| | | typename std::decay<T>::type |
| | | >::value>::apply_tuple(std::forward<F>(f), std::forward<T>(t)); |
| | | typename std::decay<T>::type>::value>::apply_tuple(std::forward<F>(f), std::forward<T>(t)); |
| | | } |
| | | |
| | | #endif // C++17 |
| | |
| | | service_type& context() NOEXCEPT { return _service; } |
| | | |
| | | private: |
| | | |
| | | class event_item : public qtl::event |
| | | { |
| | | public: |
| | |
| | | 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); |
| | |
| | | else |
| | | handler(qtl::event::ef_exception); |
| | | _busying = false; |
| | | _timer.cancel(); |
| | | })); |
| | | _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) { |
| | | _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 |
| | | handler(qtl::event::ef_exception); |
| | | _timer.cancel(); |
| | | _busying = false; |
| | | })); |
| | | _busying = false; })); |
| | | _busying = true; |
| | | } |
| | | if (timeout > 0) |
| | |
| | | #else |
| | | _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 (_busying) |
| | | return; |
| | | #if ASIO_VERSION >= 101200 && (!defined(_WIN32) || _WIN32_WINNT >= 0x0603 ) |
| | | _socket.release(); |
| | | #endif //Windows 8.1 |
| | |
| | | }; |
| | | |
| | | public: |
| | | |
| | | template<typename Connection> |
| | | event_item* add(Connection* connection) |
| | | { |
| | |
| | | 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); |
| | | 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 |
| | | async_init_type<OpenHandler, |
| | | void(typename Connection::exception_type)> init(std::forward<OpenHandler>(handler)); |
| | | void(typename Connection::exception_type)> |
| | | init(std::forward<OpenHandler>(handler)); |
| | | #else |
| | | async_init_type<OpenHandler, |
| | | void(typename Connection::exception_type)> init(handler); |
| | | void(typename Connection::exception_type)> |
| | | init(handler); |
| | | #endif |
| | | |
| | | db.open(service, get_async_handler(init), std::forward<Args>(args)...); |
| | |
| | | { |
| | | #if ASIO_VERSION < 101200 |
| | | async_init_type<CloseHandler, |
| | | void()> init(std::forward<CloseHandler>(std::forward<CloseHandler>(handler))); |
| | | void()> |
| | | init(std::forward<CloseHandler>(std::forward<CloseHandler>(handler))); |
| | | #else |
| | | async_init_type<CloseHandler, |
| | | void()> init(std::forward<CloseHandler>(handler)); |
| | | void()> |
| | | init(std::forward<CloseHandler>(handler)); |
| | | #endif |
| | | |
| | | db.close(get_async_handler(init), std::forward<Args>(args)...); |
| | |
| | | { |
| | | #if ASIO_VERSION < 101200 |
| | | async_init_type<ExecuteHandler, |
| | | void(typename Connection::exception_type, uint64_t)> init(std::forward<ExecuteHandler>(handler)); |
| | | 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); |
| | | void(typename Connection::exception_type, uint64_t)> |
| | | init(handler); |
| | | #endif |
| | | |
| | | db.execute(get_async_handler(init), std::forward<Args>(args)...); |
| | |
| | | { |
| | | #if ASIO_VERSION < 101200 |
| | | async_init_type<ExecuteHandler, |
| | | void(typename Connection::exception_type, uint64_t)> init(std::forward<ExecuteHandler>(handler)); |
| | | 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); |
| | | void(typename Connection::exception_type, uint64_t)> |
| | | init(handler); |
| | | #endif |
| | | |
| | | db.execute_direct(get_async_handler(init), std::forward<Args>(args)...); |
| | |
| | | { |
| | | #if ASIO_VERSION < 101200 |
| | | async_init_type<ExecuteHandler, |
| | | void(typename Connection::exception_type, uint64_t)> init(std::forward<ExecuteHandler>(handler)); |
| | | 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); |
| | | void(typename Connection::exception_type, uint64_t)> |
| | | init(handler); |
| | | #endif |
| | | |
| | | db.insert(get_async_handler(init), std::forward<Args>(args)...); |
| | |
| | | { |
| | | #if ASIO_VERSION < 101200 |
| | | async_init_type<ExecuteHandler, |
| | | void(typename Connection::exception_type, uint64_t)> init(std::forward<ExecuteHandler>(handler)); |
| | | 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); |
| | | void(typename Connection::exception_type, uint64_t)> |
| | | init(handler); |
| | | #endif |
| | | |
| | | db.insert_direct(get_async_handler(init), std::forward<Args>(args)...); |
| | |
| | | { |
| | | #if ASIO_VERSION < 101200 |
| | | async_init_type<FinishHandler, |
| | | void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler)); |
| | | void(typename Connection::exception_type)> |
| | | init(std::forward<FinishHandler>(handler)); |
| | | #else |
| | | async_init_type<FinishHandler, |
| | | void(typename Connection::exception_type)> init(handler); |
| | | void(typename Connection::exception_type)> |
| | | init(handler); |
| | | #endif |
| | | |
| | | db.query(std::forward<Args>(args)..., get_async_handler(init)); |
| | |
| | | { |
| | | #if ASIO_VERSION < 101200 |
| | | async_init_type<FinishHandler, |
| | | void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler)); |
| | | void(typename Connection::exception_type)> |
| | | init(std::forward<FinishHandler>(handler)); |
| | | #else |
| | | async_init_type<FinishHandler, |
| | | void(typename Connection::exception_type)> init(handler); |
| | | void(typename Connection::exception_type)> |
| | | init(handler); |
| | | #endif |
| | | |
| | | db.query_explicit(std::forward<Args>(args)..., get_async_handler(init)); |
| | |
| | | { |
| | | #if ASIO_VERSION < 101200 |
| | | async_init_type<FinishHandler, |
| | | void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler)); |
| | | void(typename Connection::exception_type)> |
| | | init(std::forward<FinishHandler>(handler)); |
| | | #else |
| | | async_init_type<FinishHandler, |
| | | void(typename Connection::exception_type)> init(handler); |
| | | 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)...); |
| | |
| | | { |
| | | #if ASIO_VERSION < 101200 |
| | | async_init_type<FinishHandler, |
| | | void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler)); |
| | | void(typename Connection::exception_type)> |
| | | init(std::forward<FinishHandler>(handler)); |
| | | #else |
| | | async_init_type<FinishHandler, |
| | | void(typename Connection::exception_type)> init(handler); |
| | | 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)...); |
| | |
| | | { |
| | | #if ASIO_VERSION < 101200 |
| | | async_init_type<FinishHandler, |
| | | void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler)); |
| | | void(typename Connection::exception_type)> |
| | | init(std::forward<FinishHandler>(handler)); |
| | | #else |
| | | async_init_type<FinishHandler, |
| | | void(typename Connection::exception_type)> init(handler); |
| | | 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)...); |
| | |
| | | { |
| | | #if ASIO_VERSION < 101200 |
| | | async_init_type<FinishHandler, |
| | | void(typename Connection::exception_type)> init(std::forward<FinishHandler>(handler)); |
| | | void(typename Connection::exception_type)> |
| | | init(std::forward<FinishHandler>(handler)); |
| | | #else |
| | | async_init_type<FinishHandler, |
| | | void(typename Connection::exception_type)> init(handler); |
| | | void(typename Connection::exception_type)> |
| | | init(handler); |
| | | #endif |
| | | |
| | | db.query_multi(std::forward<A1>(a1), get_async_handler(init), std::forward<RowHandlers>(row_handlers)...); |
| | |
| | | void start(const std::shared_ptr<Command>& command) |
| | | { |
| | | auto self = this->shared_from_this(); |
| | | command->fetch(std::forward<Values>(m_values), [this, command]() { |
| | | return qtl::detail::apply<RowHandler, Values>(std::forward<RowHandler>(m_row_handler), std::forward<Values>(m_values)); |
| | | }, [self, command](const Exception& e) { |
| | | command->fetch(std::forward<Values>(m_values), [this, command]() |
| | | { return qtl::detail::apply<RowHandler, Values>(std::forward<RowHandler>(m_row_handler), std::forward<Values>(m_values)); }, [self, command](const Exception &e) |
| | | { |
| | | if (e || self->m_auto_close_command) |
| | | { |
| | | command->close([self, command, e](const Exception& new_e) { |
| | |
| | | else |
| | | { |
| | | self->m_finish_handler(e); |
| | | } |
| | | }); |
| | | } }); |
| | | } |
| | | |
| | | void auto_close_command(bool auto_close) |
| | |
| | | return std::make_shared<async_fetch_helper<Values, RowHandler, FinishHandler>>(values, row_handler, cpmplete_handler); |
| | | } |
| | | |
| | | |
| | | template<typename Exception, typename Command, typename RowHandler, typename FinishHandler> |
| | | inline void async_fetch_command(const std::shared_ptr<Command>& command, FinishHandler&& finish_handler, RowHandler&& row_handler) |
| | | { |
| | |
| | | template<typename Exception, typename Command, typename RowHandler, typename FinishHandler, typename... OtherHandler> |
| | | inline void async_fetch_command(const std::shared_ptr<Command>& command, FinishHandler&& finish_handler, RowHandler&& row_handler, OtherHandler&&... other) |
| | | { |
| | | async_fetch_command<Exception>(command, [command, finish_handler, other...](const Exception& e) mutable { |
| | | async_fetch_command<Exception>(command, [command, finish_handler, other...](const Exception &e) mutable |
| | | { |
| | | if (e) |
| | | { |
| | | finish_handler(e); |
| | |
| | | else |
| | | async_fetch_command<Exception>(command, std::forward<FinishHandler>(finish_handler), std::forward<OtherHandler>(other)...); |
| | | }); |
| | | } |
| | | }, std::forward<RowHandler>(row_handler)); |
| | | } }, std::forward<RowHandler>(row_handler)); |
| | | } |
| | | |
| | | } |
| | |
| | | void execute(ResultHandler handler, const char* query_text, size_t text_length, const Params& params) |
| | | { |
| | | T* pThis = static_cast<T*>(this); |
| | | pThis->open_command(query_text, text_length, [handler, params](const typename T::exception_type& e, std::shared_ptr<Command>& command) mutable { |
| | | pThis->open_command(query_text, text_length, [handler, params](const typename T::exception_type &e, std::shared_ptr<Command> &command) mutable |
| | | { |
| | | if(e) |
| | | { |
| | | command->close([command, e, handler](const typename T::exception_type& ae) mutable { |
| | |
| | | command->close([command, handler, e, affected](const typename T::exception_type& ae) mutable { |
| | | handler(e ? e : ae, affected); |
| | | }); |
| | | }); |
| | | }); |
| | | }); }); |
| | | } |
| | | template<typename Params, typename ResultHandler> |
| | | void execute(ResultHandler handler, const char* query_text, const Params& params) |
| | |
| | | void insert(ResultHandler handler, const char* query_text, size_t text_length, const Params& params) |
| | | { |
| | | T* pThis = static_cast<T*>(this); |
| | | pThis->open_command(query_text, text_length, [handler, params](const typename T::exception_type& e, std::shared_ptr<Command>& command) { |
| | | pThis->open_command(query_text, text_length, [handler, params](const typename T::exception_type &e, std::shared_ptr<Command> &command) |
| | | { |
| | | if(e) |
| | | { |
| | | command->close([command, e, handler](const typename T::exception_type& ae) mutable { |
| | |
| | | handler(e ? e : ae, insert_id); |
| | | }); |
| | | }); |
| | | } |
| | | }); |
| | | } }); |
| | | } |
| | | |
| | | template<typename Params, typename ResultHandler> |
| | |
| | | void query_explicit(const char* query_text, size_t text_length, const Params& params, Values&& values, RowHandler&& row_handler, FinishHandler&& finish_handler) |
| | | { |
| | | T* pThis = static_cast<T*>(this); |
| | | pThis->open_command(query_text, text_length, [values, row_handler, finish_handler, params](const typename T::exception_type& e, const std::shared_ptr<Command>& command) mutable { |
| | | pThis->open_command(query_text, text_length, [values, row_handler, finish_handler, params](const typename T::exception_type &e, const std::shared_ptr<Command> &command) mutable |
| | | { |
| | | if(e) |
| | | { |
| | | finish_handler(e); |
| | |
| | | auto helper=detail::make_fetch_helper(values, row_handler, finish_handler); |
| | | helper->template start<Command, typename T::exception_type>(command); |
| | | }); |
| | | } |
| | | }); |
| | | } }); |
| | | } |
| | | |
| | | template<typename Params, typename Values, typename RowHandler, typename FinishHandler> |
| | |
| | | void query_multi_with_params(const char* query_text, size_t text_length, const Params& params, FinishHandler&& finish_handler, RowHandlers&&... row_handlers) |
| | | { |
| | | T* pThis = static_cast<T*>(this); |
| | | pThis->open_command(query_text, text_length, [params, finish_handler, row_handlers...](const typename T::exception_type& e, const std::shared_ptr<Command>& command) mutable { |
| | | pThis->open_command(query_text, text_length, [params, finish_handler, row_handlers...](const typename T::exception_type &e, const std::shared_ptr<Command> &command) mutable |
| | | { |
| | | if (e) |
| | | { |
| | | finish_handler(e); |
| | |
| | | else |
| | | qtl::detail::async_fetch_command<typename T::exception_type>(command, std::forward<FinishHandler>(finish_handler), std::forward<RowHandlers>(row_handlers)...); |
| | | }); |
| | | } |
| | | }); |
| | | } }); |
| | | } |
| | | template<typename Params, typename FinishHandler, typename... RowHandlers> |
| | | void query_multi_with_params(const char* query_text, const Params& params, FinishHandler&& finish_handler, RowHandlers&&... row_handlers) |
| | |
| | | namespace qtl |
| | | { |
| | | |
| | | struct null { }; |
| | | struct null |
| | | { |
| | | }; |
| | | |
| | | struct blob_data |
| | | { |
| | |
| | | } |
| | | |
| | | void clear() { m_value.clear(); } |
| | | char_type* alloc(size_t n) { m_value.resize(n); return (char_type*)m_value.data(); } |
| | | char_type *alloc(size_t n) |
| | | { |
| | | m_value.resize(n); |
| | | return (char_type *)m_value.data(); |
| | | } |
| | | void truncate(size_t n) { m_value.resize(n); } |
| | | void assign(const char_type* str, size_t n) { m_value.assign(str, n); } |
| | | const char_type* data() const { return m_value.data(); } |
| | | size_t size() const { return m_value.size(); } |
| | | |
| | | private: |
| | | string_type&& m_value; |
| | | }; |
| | |
| | | size_t index=command.find_field(name); |
| | | if (index == -1) |
| | | { |
| | | if (length > 0) value[0] = '\0'; |
| | | if (length > 0) |
| | | value[0] = '\0'; |
| | | } |
| | | else |
| | | command.bind_field(index, value, length); |
| | |
| | | size_t index=command.find_field(name); |
| | | if (index == -1) |
| | | { |
| | | if (length > 0) value[0] = '\0'; |
| | | if (length > 0) |
| | | value[0] = '\0'; |
| | | } |
| | | else |
| | | command.bind_field(index, value, length); |
| | |
| | | typedef typename std::result_of<F(T)>::type raw_result_type; |
| | | #endif |
| | | template<typename Ret, bool> |
| | | struct impl {}; |
| | | struct impl |
| | | { |
| | | }; |
| | | template<typename Ret> |
| | | struct impl<Ret, true> |
| | | { |
| | |
| | | typedef typename std::result_of<F(Types...)>::type raw_result_type; |
| | | #endif |
| | | template<typename Ret, bool> |
| | | struct impl {}; |
| | | struct impl |
| | | { |
| | | }; |
| | | template<typename Ret> |
| | | struct impl<Ret, true> |
| | | { |
| | |
| | | typedef R (Type::*fun_type)(); |
| | | typedef R raw_result_type; |
| | | template<typename Ret, bool> |
| | | struct impl {}; |
| | | struct impl |
| | | { |
| | | }; |
| | | template<typename Ret> |
| | | struct impl<Ret, true> |
| | | { |
| | |
| | | typedef R (Type::*fun_type)() const; |
| | | typedef R raw_result_type; |
| | | template<typename Ret, bool> |
| | | struct impl {}; |
| | | struct impl |
| | | { |
| | | }; |
| | | template<typename Ret> |
| | | struct impl<Ret, true> |
| | | { |
| | |
| | | bind_field(m_command, N-1, std::forward<param_type>(std::get<N-1>(std::forward<tuple_type>(params)))); |
| | | (bind_helper<Command, N-1, Types...>(m_command))(std::forward<tuple_type>(params)); |
| | | } |
| | | |
| | | private: |
| | | typedef std::tuple<Types...> tuple_type; |
| | | Command& m_command; |
| | |
| | | typedef typename std::remove_reference<typename std::tuple_element<0, tuple_type>::type>::type param_type; |
| | | bind_field(m_command, static_cast<size_t>(0), std::forward<param_type>(std::get<0>(std::forward<tuple_type>(params)))); |
| | | } |
| | | |
| | | private: |
| | | typedef std::tuple<Types...> tuple_type; |
| | | Command& m_command; |
| | |
| | | template<typename Command, typename T> |
| | | struct params_binder |
| | | { |
| | | enum { size = 1 }; |
| | | enum |
| | | { |
| | | size = 1 |
| | | }; |
| | | inline void operator()(Command& command, const T& param) const |
| | | { |
| | | qtl::bind_param(command, 0, param); |
| | |
| | | template<typename Command, typename... Types> |
| | | struct params_binder<Command, std::tuple<Types...>> |
| | | { |
| | | enum { size = sizeof...(Types) }; |
| | | enum |
| | | { |
| | | size = sizeof...(Types) |
| | | }; |
| | | void operator()(Command& command, const std::tuple<Types...>& params) const |
| | | { |
| | | (detail::bind_helper<Command, std::tuple_size<std::tuple<Types...>>::value, Types...>(command))(params); |
| | |
| | | template<typename Command, typename Type1, typename Type2> |
| | | struct params_binder<Command, std::pair<Type1, Type2>> |
| | | { |
| | | enum { size = 2 }; |
| | | enum |
| | | { |
| | | size = 2 |
| | | }; |
| | | void operator()(Command& command, std::pair<Type1, Type2>&& values) const |
| | | { |
| | | qtl::bind_param(command, 0, std::forward<Type1>(values.first)); |
| | |
| | | { |
| | | void operator()(Command& command, std::tuple<Types...>&& values) const |
| | | { |
| | | (detail::bind_helper<Command, std::tuple_size<std::tuple<Types...>>::value, Types...>(command)) |
| | | (std::forward<std::tuple<Types...>>(values)); |
| | | (detail::bind_helper<Command, std::tuple_size<std::tuple<Types...>>::value, Types...>(command))(std::forward<std::tuple<Types...>>(values)); |
| | | } |
| | | }; |
| | | |
| | |
| | | private: |
| | | Pred m_pred; |
| | | }; |
| | | |
| | | |
| | | template<typename T, typename Pred> |
| | | inline custom_binder_type<T, Pred> custom_bind(T&& v, Pred pred) |
| | |
| | | T* pThis=static_cast<T*>(this); |
| | | Command command=pThis->open_command(query_text, text_length); |
| | | command.execute(params); |
| | | if(affected) *affected=command.affetced_rows(); |
| | | if (affected) |
| | | *affected = command.affetced_rows(); |
| | | command.close(); |
| | | return *this; |
| | | } |
| | |
| | | command.execute(params); |
| | | while(command.fetch(std::forward<Values>(values))) |
| | | { |
| | | if(!detail::apply(std::forward<ValueProc>(proc), std::forward<Values>(values))) break; |
| | | if (!detail::apply(std::forward<ValueProc>(proc), std::forward<Values>(values))) |
| | | break; |
| | | } |
| | | command.close(); |
| | | return *this; |
| | |
| | | protected: |
| | | struct nothing |
| | | { |
| | | template<typename... Values> bool operator()(Values&&...) const { return true; } |
| | | template <typename... Values> |
| | | bool operator()(Values &&...) const { return true; } |
| | | }; |
| | | struct first_record |
| | | { |
| | | first_record() : _found(false) { } |
| | | template<typename... Values> bool operator()(Values&&...) { _found = true; return false; } |
| | | template <typename... Values> |
| | | bool operator()(Values &&...) |
| | | { |
| | | _found = true; |
| | | return false; |
| | | } |
| | | operator bool() const { return _found; } |
| | | |
| | | private: |
| | |
| | | // eback()[intersection.first - m_pos] = c; |
| | | //} |
| | | m_pos += 1; |
| | | |
| | | } |
| | | return ch; |
| | | } |
| | | |
| | | virtual int_type pbackfail(int_type c = traits_type::eof()) override |
| | | { |
| | | if (gptr() == 0 |
| | | || gptr() <= eback() |
| | | || (!traits_type::eq_int_type(traits_type::eof(), c) |
| | | && !traits_type::eq(traits_type::to_char_type(c), gptr()[-1]))) |
| | | if (gptr() == 0 || gptr() <= eback() || (!traits_type::eq_int_type(traits_type::eof(), c) && !traits_type::eq(traits_type::to_char_type(c), gptr()[-1]))) |
| | | { |
| | | return (traits_type::eof()); // can't put back, fail |
| | | } |
| | |
| | | } |
| | | |
| | | private: |
| | | |
| | | off_type seekoff(off_type position, off_type off, std::ios_base::seekdir dir) |
| | | { |
| | | off_type result = 0; |
| | |
| | | m_commited=true; |
| | | } |
| | | } |
| | | |
| | | private: |
| | | bool m_commited; |
| | | Database& m_db; |
| | |
| | | { |
| | | command.reset(); |
| | | command.execute(params); |
| | | if(affected) *affected+=command.affetced_rows(); |
| | | if (affected) |
| | | *affected += command.affetced_rows(); |
| | | } |
| | | |
| | | template<typename Command, typename Params, typename... Others> |
| | |
| | | Database* db=popup(); |
| | | if(db==NULL && m_trying_connection==false) |
| | | db=create_database(); |
| | | return pointer(db, [this](Database* db) { |
| | | recovery(db); |
| | | }); |
| | | return pointer(db, [this](Database *db) |
| | | { recovery(db); }); |
| | | } |
| | | |
| | | bool test_alive() |
| | |
| | | try_connect(); |
| | | return false; |
| | | } |
| | | else return true; |
| | | else |
| | | return true; |
| | | } |
| | | |
| | | private: |
| | |
| | | virtual Database* new_database() throw()=0; |
| | | void recovery(Database* db) |
| | | { |
| | | if(db==NULL) return; |
| | | if (db == NULL) |
| | | return; |
| | | if(db->is_alive()) |
| | | { |
| | | std::lock_guard<std::mutex> lock(m_pool_mutex); |
| | |
| | | Database* create_database() |
| | | { |
| | | Database* db=new_database(); |
| | | if(db) return db; |
| | | if (db) |
| | | return db; |
| | | |
| | | { |
| | | std::lock_guard<std::mutex> lock(m_pool_mutex); |
| | |
| | | if(db==NULL) |
| | | { |
| | | std::this_thread::sleep_for(std::chrono::seconds(interval)); |
| | | if(interval<60) interval<<=1; |
| | | if (interval < 60) |
| | | interval <<= 1; |
| | | } |
| | | } |
| | | if(db) |
| | |
| | | void get(Handler&& handler, EventLoop* ev=nullptr) |
| | | { |
| | | Connection* db = popup(); |
| | | if(ev==nullptr) ev=&m_ev; |
| | | if (ev == nullptr) |
| | | ev = &m_ev; |
| | | |
| | | if(db) |
| | | { |
| | |
| | | } |
| | | else if (m_trying_connecting == false) |
| | | { |
| | | create_connection(ev, [this, handler](const typename Connection::exception_type& e, Connection* db) { |
| | | handler(e, wrap(db)); |
| | | }); |
| | | create_connection(ev, [this, handler](const typename Connection::exception_type &e, Connection *db) |
| | | { handler(e, wrap(db)); }); |
| | | } |
| | | else |
| | | { |
| | |
| | | while (it != m_connections.end()) |
| | | { |
| | | Connection* db = *it; |
| | | db->is_alive([this, db](const typename Connection::exception_type& e) { |
| | | db->is_alive([this, db](const typename Connection::exception_type &e) |
| | | { |
| | | if (e) |
| | | { |
| | | std::unique_lock<std::mutex> lock(m_pool_mutex); |
| | |
| | | m_connections.erase(it); |
| | | if (m_connections.empty()) |
| | | try_connect(); |
| | | } |
| | | }); |
| | | } }); |
| | | ++it; |
| | | } |
| | | } |
| | |
| | | |
| | | void recovery(Connection* db) |
| | | { |
| | | if (db == NULL) return; |
| | | db->is_alive([this, db](const typename Connection::exception_type& e) { |
| | | if (db == NULL) |
| | | return; |
| | | db->is_alive([this, db](const typename Connection::exception_type &e) |
| | | { |
| | | if (e) |
| | | { |
| | | { |
| | |
| | | throw std::runtime_error("destroy a busysing connection."); |
| | | std::lock_guard<std::recursive_mutex> lock(m_pool_mutex); |
| | | m_connections.push_back(db); |
| | | } |
| | | }); |
| | | } }); |
| | | } |
| | | |
| | | template<typename Handler> |
| | | void create_connection(EventLoop* ev, Handler&& handler) |
| | | { |
| | | T* pThis = static_cast<T*>(this); |
| | | pThis->new_connection(*ev, [this, handler](const typename Connection::exception_type& e, Connection* db) { |
| | | pThis->new_connection(*ev, [this, handler](const typename Connection::exception_type &e, Connection *db) |
| | | { |
| | | handler(e, db); |
| | | if (!db) |
| | | { |
| | |
| | | m_ev.set_timeout(tv, [this]() { |
| | | try_connect(); |
| | | }); |
| | | } |
| | | }); |
| | | } }); |
| | | } |
| | | |
| | | Connection* popup() |
| | |
| | | return; |
| | | |
| | | m_trying_connecting = true; |
| | | create_connection(&m_ev, [this](const typename Connection::exception_type& e, Connection* db) { |
| | | create_connection(&m_ev, [this](const typename Connection::exception_type &e, Connection *db) |
| | | { |
| | | if (db) |
| | | { |
| | | std::lock_guard<std::recursive_mutex> lock(m_pool_mutex); |
| | |
| | | else |
| | | { |
| | | m_trying_connecting = false; |
| | | } |
| | | }); |
| | | } }); |
| | | } |
| | | |
| | | void clear() |
| | |
| | | { |
| | | if (db) |
| | | { |
| | | return pointer(db, [this](Connection* db) { |
| | | recovery(db); |
| | | }); |
| | | return pointer(db, [this](Connection *db) |
| | | { recovery(db); }); |
| | | } |
| | | else return nullptr; |
| | | else |
| | | return nullptr; |
| | | } |
| | | }; |
| | | |
| | |
| | | class binder : public MYSQL_BIND |
| | | { |
| | | friend class statement; |
| | | |
| | | public: |
| | | binder() |
| | | { |
| | |
| | | } |
| | | }; |
| | | |
| | | |
| | | template<typename T> |
| | | inline void bind(binder& binder, const T& v) |
| | | { |
| | |
| | | |
| | | inline void bind(binder& binder, const char* str, size_t length=0) |
| | | { |
| | | if(length==0) length=strlen(str); |
| | | if (length == 0) |
| | | length = strlen(str); |
| | | binder.bind(const_cast<char*>(str), static_cast<unsigned long>(length), MYSQL_TYPE_VAR_STRING); |
| | | } |
| | | |
| | |
| | | int code() const throw() { return m_error; } |
| | | operator bool() const { return m_error != 0; } |
| | | virtual const char* what() const NOEXCEPT override { return m_errmsg.data(); } |
| | | |
| | | private: |
| | | unsigned int m_error; |
| | | std::string m_errmsg; |
| | |
| | | m_stmt = stmt; |
| | | m_field = field; |
| | | m_binder = b; |
| | | if (b.length) m_size = *b.length; |
| | | if (b.length) |
| | | m_size = *b.length; |
| | | init_buffer(mode); |
| | | } |
| | | |
| | |
| | | void bind_param(size_t index, std::istream& param) |
| | | { |
| | | m_binders[index].bind(nullptr, 0, MYSQL_TYPE_LONG_BLOB); |
| | | m_binderAddins[index].m_after_fetch = [this, index, ¶m](const binder&) { |
| | | m_binderAddins[index].m_after_fetch = [this, index, ¶m](const binder &) |
| | | { |
| | | std::array<char, blob_buffer_size> buffer; |
| | | unsigned long readed = 0; |
| | | while (!param.eof() && !param.fail()) |
| | |
| | | void bind_param(size_t index, const blob_writer& param) |
| | | { |
| | | m_binders[index].bind(nullptr, 0, MYSQL_TYPE_LONG_BLOB); |
| | | m_binderAddins[index].m_after_fetch = [this, index, ¶m](const binder& b) { |
| | | m_binderAddins[index].m_after_fetch = [this, index, ¶m](const binder &b) |
| | | { |
| | | blobbuf buf; |
| | | buf.open(m_stmt, index, b, std::ios::out); |
| | | std::ostream s(&buf); |
| | |
| | | void bind_field(size_t index, char* value, size_t length) |
| | | { |
| | | m_binders[index].bind(value, length - 1, MYSQL_TYPE_VAR_STRING); |
| | | m_binderAddins[index].m_after_fetch = [](const binder& bind) { |
| | | m_binderAddins[index].m_after_fetch = [](const binder &bind) |
| | | { |
| | | if (*bind.is_null) |
| | | memset(bind.buffer, 0, bind.buffer_length + 1); |
| | | else |
| | |
| | | if (m_result) |
| | | { |
| | | MYSQL_FIELD* field = mysql_fetch_field_direct(m_result, (unsigned int)index); |
| | | if (field == nullptr) throw_exception(); |
| | | if (field == nullptr) |
| | | throw_exception(); |
| | | value.clear(); |
| | | typename bind_string_helper<T>::char_type* data = value.alloc(field->length); |
| | | m_binderAddins[index].m_before_fetch = [this, value](binder& b) mutable { |
| | | m_binderAddins[index].m_before_fetch = [this, value](binder &b) mutable |
| | | { |
| | | if (value.size() < b.buffer_length) |
| | | { |
| | | value.alloc(b.buffer_length); |
| | |
| | | } |
| | | } |
| | | }; |
| | | m_binderAddins[index].m_after_fetch = [value](const binder& b) mutable { |
| | | if (*b.is_null) value.clear(); |
| | | else value.truncate(*b.length); |
| | | m_binderAddins[index].m_after_fetch = [value](const binder &b) mutable |
| | | { |
| | | if (*b.is_null) |
| | | value.clear(); |
| | | else |
| | | value.truncate(*b.length); |
| | | }; |
| | | m_binders[index].bind((void*)data, field->length, field->type); |
| | | } |
| | |
| | | MYSQL_FIELD* field = mysql_fetch_field_direct(m_result, (unsigned int)index); |
| | | assert(IS_LONGDATA(field->type)); |
| | | m_binders[index].bind(nullptr, 0, field->type); |
| | | m_binderAddins[index].m_after_fetch = [this, index, &value](const binder& b) { |
| | | m_binderAddins[index].m_after_fetch = [this, index, &value](const binder &b) |
| | | { |
| | | unsigned long readed = 0; |
| | | std::array<char, blob_buffer_size> buffer; |
| | | binder& bb = const_cast<binder&>(b); |
| | | if (*b.is_null) return; |
| | | if (*b.is_null) |
| | | return; |
| | | bb.buffer = const_cast<char*>(buffer.data()); |
| | | bb.buffer_length = buffer.size(); |
| | | while (readed <= *b.length) |
| | |
| | | MYSQL_FIELD* field = mysql_fetch_field_direct(m_result, (unsigned int)index); |
| | | assert(IS_LONGDATA(field->type)); |
| | | m_binders[index].bind(nullptr, 0, field->type); |
| | | m_binderAddins[index].m_after_fetch = [this, index, &value](const binder& b) { |
| | | if (*b.is_null) return; |
| | | m_binderAddins[index].m_after_fetch = [this, index, &value](const binder &b) |
| | | { |
| | | if (*b.is_null) |
| | | return; |
| | | value.open(m_stmt, index, b, std::ios::in); |
| | | }; |
| | | } |
| | |
| | | qtl::bind_field(*this, index, value.data); |
| | | binder_addin& addin = m_binderAddins[index]; |
| | | auto fetch_fun = addin.m_after_fetch; |
| | | addin.m_after_fetch = [&addin, fetch_fun, &value](const binder& b) { |
| | | addin.m_after_fetch = [&addin, fetch_fun, &value](const binder &b) |
| | | { |
| | | value.is_null = *b.is_null != 0; |
| | | value.length = *b.length; |
| | | value.is_truncated = addin.is_truncated; |
| | | if (fetch_fun) fetch_fun(b); |
| | | if (fetch_fun) |
| | | fetch_fun(b); |
| | | }; |
| | | } |
| | | } |
| | |
| | | qtl::bind_field(*this, index, *value); |
| | | binder_addin& addin = m_binderAddins[index]; |
| | | auto fetch_fun = addin.m_after_fetch; |
| | | addin.m_after_fetch = [&addin, fetch_fun, &value](const binder& b) { |
| | | if (fetch_fun) fetch_fun(b); |
| | | if (*b.is_null) value.reset(); |
| | | addin.m_after_fetch = [&addin, fetch_fun, &value](const binder &b) |
| | | { |
| | | if (fetch_fun) |
| | | fetch_fun(b); |
| | | if (*b.is_null) |
| | | value.reset(); |
| | | }; |
| | | } |
| | | } |
| | |
| | | if (m_result) |
| | | { |
| | | MYSQL_FIELD* field = mysql_fetch_field_direct(m_result, (unsigned int)index); |
| | | if (field == nullptr) throw_exception(); |
| | | if (field == nullptr) |
| | | throw_exception(); |
| | | switch (field->type) |
| | | { |
| | | case MYSQL_TYPE_NULL: |
| | |
| | | } |
| | | binder_addin& addin = m_binderAddins[index]; |
| | | auto fetch_fun = addin.m_after_fetch; |
| | | addin.m_after_fetch = [&addin, fetch_fun, &value](const binder& b) { |
| | | if (fetch_fun) fetch_fun(b); |
| | | if (*b.is_null) value.reset(); |
| | | addin.m_after_fetch = [&addin, fetch_fun, &value](const binder &b) |
| | | { |
| | | if (fetch_fun) |
| | | fetch_fun(b); |
| | | if (*b.is_null) |
| | | value.reset(); |
| | | }; |
| | | } |
| | | } |
| | |
| | | explicit if_null(Value& value, Value&& def=Value()) : m_value(value), m_def(std::move(def)) { } |
| | | void operator()(const binder& b) |
| | | { |
| | | if(*b.is_null) m_value=m_def; |
| | | if (*b.is_null) |
| | | m_value = m_def; |
| | | } |
| | | Value& m_value; |
| | | Value m_def; |
| | | }; |
| | | |
| | | }; |
| | | |
| | | class statement : public base_statement |
| | |
| | | void open(const char *query_text, unsigned long text_length=0) |
| | | { |
| | | mysql_stmt_reset(m_stmt); |
| | | if(text_length==0) text_length=(unsigned long)strlen(query_text); |
| | | if (text_length == 0) |
| | | text_length = (unsigned long)strlen(query_text); |
| | | if(mysql_stmt_prepare(m_stmt, query_text, text_length)!=0) |
| | | throw_exception(); |
| | | } |
| | |
| | | template<typename Types> |
| | | void execute(const Types& params) |
| | | { |
| | | execute_custom([¶ms](statement& stmt) { |
| | | qtl::bind_params(stmt, params); |
| | | }); |
| | | execute_custom([¶ms](statement &stmt) |
| | | { qtl::bind_params(stmt, params); }); |
| | | } |
| | | |
| | | template<typename Types> |
| | |
| | | if(count>0) |
| | | { |
| | | m_result=mysql_stmt_result_metadata(m_stmt); |
| | | if(m_result==nullptr) throw_exception(); |
| | | if (m_result == nullptr) |
| | | throw_exception(); |
| | | resize_binders(count); |
| | | qtl::bind_record(*this, std::forward<Types>(values)); |
| | | set_binders(); |
| | |
| | | do |
| | | { |
| | | ret=mysql_stmt_next_result(m_stmt); |
| | | if(ret>0) throw_exception(); |
| | | if (ret > 0) |
| | | throw_exception(); |
| | | }while(ret==0 && mysql_stmt_field_count(m_stmt)<=0); |
| | | return ret==0; |
| | | } |
| | |
| | | bool open(const char *host, const char *user, const char *passwd, const char *db, |
| | | unsigned long clientflag = 0, unsigned int port = 0, const char *unix_socket = nullptr) |
| | | { |
| | | if (m_mysql == nullptr) m_mysql = mysql_init(nullptr); |
| | | if (m_mysql == nullptr) |
| | | m_mysql = mysql_init(nullptr); |
| | | return mysql_real_connect(m_mysql, host, user, passwd, db, port, unix_socket, clientflag) != nullptr; |
| | | } |
| | | void close() |
| | |
| | | { |
| | | if (mysql_query(m_mysql, query_text) != 0) |
| | | throw_exception(); |
| | | if (paffected) *paffected = affected_rows(); |
| | | if (paffected) |
| | | *paffected = affected_rows(); |
| | | } |
| | | void simple_execute(const char* query_text, unsigned long text_length, uint64_t* paffected = nullptr) |
| | | { |
| | | if (text_length == 0) text_length = (unsigned long)strlen(query_text); |
| | | if (text_length == 0) |
| | | text_length = (unsigned long)strlen(query_text); |
| | | if (mysql_real_query(m_mysql, query_text, text_length) != 0) |
| | | throw_exception(); |
| | | if (paffected) *paffected = affected_rows(); |
| | | if (paffected) |
| | | *paffected = affected_rows(); |
| | | } |
| | | |
| | | void auto_commit(bool on) |
| | |
| | | async_connection async_mode(); |
| | | |
| | | #endif //MariaDB |
| | | |
| | | }; |
| | | |
| | | #if MARIADB_VERSION_ID >= 100000 |
| | |
| | | template<typename Handler> |
| | | void open(Handler&& handler, const char *query_text, size_t text_length=0) |
| | | { |
| | | if(text_length==0) text_length=strlen(query_text); |
| | | if (text_length == 0) |
| | | text_length = strlen(query_text); |
| | | if(m_stmt) |
| | | { |
| | | std::string text(query_text, text_length); |
| | | reset([this, text, handler](const mysql::error& e) mutable { |
| | | reset([this, text, handler](const mysql::error &e) mutable |
| | | { |
| | | if(e) |
| | | { |
| | | handler(e); |
| | | return; |
| | | } |
| | | |
| | | prepare(text.data(), text.size(), std::forward<Handler>(handler)); |
| | | }); |
| | | prepare(text.data(), text.size(), std::forward<Handler>(handler)); }); |
| | | } |
| | | else |
| | | { |
| | |
| | | if(count>0) |
| | | { |
| | | m_result=mysql_stmt_result_metadata(m_stmt); |
| | | if(m_result==nullptr) throw_exception(); |
| | | if (m_result == nullptr) |
| | | throw_exception(); |
| | | resize_binders(count); |
| | | qtl::bind_record(*this, std::forward<Types>(values)); |
| | | set_binders(); |
| | |
| | | int status = mysql_stmt_free_result_start(&ret, m_stmt); |
| | | if(status) |
| | | { |
| | | this->wait_free_result(status, [this, handler](const mysql::error& e) mutable { |
| | | this->wait_free_result(status, [this, handler](const mysql::error &e) mutable |
| | | { |
| | | m_result=nullptr; |
| | | if (e) |
| | | handler(e); |
| | | else |
| | | close(handler); |
| | | }); |
| | | close(handler); }); |
| | | } |
| | | else if(ret) |
| | | handler(mysql::error(*this)); |
| | |
| | | int status = mysql_stmt_close_start(&ret, m_stmt); |
| | | if(status) |
| | | { |
| | | wait_operation<my_bool>(status, &mysql_stmt_close_cont, [this, handler](const mysql::error& e) mutable { |
| | | wait_operation<my_bool>(status, &mysql_stmt_close_cont, [this, handler](const mysql::error &e) mutable |
| | | { |
| | | m_stmt=nullptr; |
| | | handler(e); |
| | | });; |
| | | handler(e); }); |
| | | ; |
| | | } |
| | | else |
| | | { |
| | |
| | | handler((ret) ? mysql::error(*this) : mysql::error()); |
| | | } |
| | | |
| | | |
| | | private: |
| | | event* m_event; |
| | | |
| | |
| | | void wait_operation(int status, Func func, Handler&& handler) |
| | | { |
| | | m_event->set_io_handler(event_flags(status), mysql_get_timeout_value(m_stmt->mysql), |
| | | [this, func, handler](int flags) mutable { |
| | | [this, func, handler](int flags) mutable |
| | | { |
| | | Ret ret = 0; |
| | | int status = func(&ret, m_stmt, mysql_status(flags)); |
| | | if (status) |
| | |
| | | void wait_execute(int status, ExecuteHandler&& handler) |
| | | { |
| | | m_event->set_io_handler(event_flags(status), mysql_get_timeout_value(m_stmt->mysql), |
| | | [this, handler](int flags) mutable { |
| | | [this, handler](int flags) mutable |
| | | { |
| | | int ret = 0; |
| | | int status = mysql_stmt_execute_cont(&ret, m_stmt, mysql_status(flags)); |
| | | if (status) |
| | |
| | | void wait_fetch(int status, RowHandler&& row_handler, FinishHandler&& finish_handler) |
| | | { |
| | | m_event->set_io_handler(event_flags(status), mysql_get_timeout_value(m_stmt->mysql), |
| | | [this, row_handler, finish_handler](int flags) mutable { |
| | | [this, row_handler, finish_handler](int flags) mutable |
| | | { |
| | | int ret = 0; |
| | | int status = mysql_stmt_fetch_cont(&ret, m_stmt, mysql_status(flags)); |
| | | if (status == 0) |
| | |
| | | void wait_free_result(int status, ResultHandler&& handler) NOEXCEPT |
| | | { |
| | | m_event->set_io_handler(event_flags(status), mysql_get_timeout_value(m_stmt->mysql), |
| | | [this, handler](int flags) mutable { |
| | | [this, handler](int flags) mutable |
| | | { |
| | | my_bool ret = false; |
| | | int status = mysql_stmt_free_result_cont(&ret, m_stmt, mysql_status(flags)); |
| | | if (status) |
| | |
| | | void wait_next_result(int status, Handler&& handler) |
| | | { |
| | | m_event->set_io_handler(event_flags(status), mysql_get_timeout_value(m_stmt->mysql), |
| | | [this, handler](int flags) mutable { |
| | | [this, handler](int flags) mutable |
| | | { |
| | | int ret = 0; |
| | | int status = mysql_stmt_next_result_cont(&ret, m_stmt, mysql_status(flags)); |
| | | if (status) |
| | |
| | | next_result(std::forward<Handler>(handler)); |
| | | }); |
| | | } |
| | | |
| | | }; |
| | | |
| | | class async_connection : public basic_database, public qtl::async_connection<async_connection, async_statement> |
| | |
| | | int status = mysql_close_start(m_mysql); |
| | | if (status) |
| | | { |
| | | wait_close(status, [this, handler]() mutable { |
| | | wait_close(status, [this, handler]() mutable |
| | | { |
| | | handler(); |
| | | m_mysql = nullptr; |
| | | }); |
| | | m_mysql = nullptr; }); |
| | | } |
| | | else |
| | | { |
| | |
| | | int status = mysql_query_start(&ret, m_mysql, query_text); |
| | | if (status) |
| | | { |
| | | wait_operation(status, &mysql_query_cont, [this, handler](const mysql::error& e) { |
| | | wait_operation(status, &mysql_query_cont, [this, handler](const mysql::error &e) |
| | | { |
| | | uint64_t affected = 0; |
| | | if (!e) affected = affected_rows(); |
| | | handler(e, affected); |
| | | }); |
| | | handler(e, affected); }); |
| | | } |
| | | else |
| | | { |
| | | uint64_t affected = 0; |
| | | if (ret >= 0) affected = affected_rows(); |
| | | if (ret >= 0) |
| | | affected = affected_rows(); |
| | | handler((ret) ? mysql::error(*this) : mysql::error(), affected); |
| | | } |
| | | } |
| | |
| | | int status = mysql_real_query_start(&ret, m_mysql, query_text, text_length); |
| | | if (status) |
| | | { |
| | | wait_operation(status, &mysql_real_query_cont, [this, handler](const mysql::error& e) mutable { |
| | | wait_operation(status, &mysql_real_query_cont, [this, handler](const mysql::error &e) mutable |
| | | { |
| | | uint64_t affected = 0; |
| | | if (!e) affected = affected_rows(); |
| | | handler(e, affected); |
| | | }); |
| | | handler(e, affected); }); |
| | | } |
| | | else |
| | | { |
| | | uint64_t affected = 0; |
| | | if (ret >= 0) affected = affected_rows(); |
| | | if (ret >= 0) |
| | | affected = affected_rows(); |
| | | handler((ret) ? mysql::error(*this) : mysql::error(), affected); |
| | | } |
| | | } |
| | |
| | | template<typename RowHandler, typename ResultHandler> |
| | | void simple_query(const char* query, unsigned long length, RowHandler&& row_handler, ResultHandler&& result_handler) NOEXCEPT |
| | | { |
| | | simple_execute([this, row_handler, result_handler](const mysql::error& e, uint64_t affected) mutable { |
| | | simple_execute([this, row_handler, result_handler](const mysql::error &e, uint64_t affected) mutable |
| | | { |
| | | if (e) |
| | | { |
| | | result_handler(e, 0); |
| | |
| | | else |
| | | { |
| | | result_handler(mysql::error(), 0); |
| | | } |
| | | }, query, length); |
| | | } }, query, length); |
| | | } |
| | | |
| | | template<typename Handler> |
| | | void open_command(const char* query_text, size_t text_length, Handler&& handler) |
| | | { |
| | | std::shared_ptr<async_statement> stmt=std::make_shared<async_statement>(*this); |
| | | stmt->open([stmt, handler](const mysql::error& e) mutable { |
| | | handler(e, stmt); |
| | | }, query_text, (unsigned long)text_length); |
| | | stmt->open([stmt, handler](const mysql::error &e) mutable |
| | | { handler(e, stmt); }, query_text, (unsigned long)text_length); |
| | | } |
| | | |
| | | socket_type socket() const NOEXCEPT { return mysql_get_socket(m_mysql); } |
| | |
| | | void wait_connect(int status, OpenHandler&& handler) NOEXCEPT |
| | | { |
| | | m_event_handler->set_io_handler(event_flags(status), mysql_get_timeout_value(m_mysql), |
| | | [this, handler](int flags) mutable { |
| | | [this, handler](int flags) mutable |
| | | { |
| | | MYSQL* ret = nullptr; |
| | | int status = mysql_real_connect_cont(&ret, m_mysql, mysql_status(flags)); |
| | | if (status) |
| | |
| | | void wait_close(int status, CloseHandler&& handler) NOEXCEPT |
| | | { |
| | | m_event_handler->set_io_handler(event_flags(status), mysql_get_timeout_value(m_mysql), |
| | | [this, handler](int flags) mutable { |
| | | [this, handler](int flags) mutable |
| | | { |
| | | MYSQL* ret = nullptr; |
| | | int status = mysql_close_cont(m_mysql, mysql_status(flags)); |
| | | if (status) |
| | |
| | | void wait_operation(int status, Func func, Handler&& handler) NOEXCEPT |
| | | { |
| | | m_event_handler->set_io_handler(event_flags(status), mysql_get_timeout_value(m_mysql), |
| | | [this, func, handler](int flags) mutable { |
| | | [this, func, handler](int flags) mutable |
| | | { |
| | | int ret = 0; |
| | | int status = func(&ret, m_mysql, mysql_status(flags)); |
| | | if (status) |
| | |
| | | void wait_query(int status, int field_count, RowHandler&& row_handler, ResultHandler&& result_handler) NOEXCEPT |
| | | { |
| | | m_event_handler->set_io_handler(event_flags(status), mysql_get_timeout_value(m_mysql), |
| | | [this, field_count, row_handler, result_handler](int flags) mutable { |
| | | [this, field_count, row_handler, result_handler](int flags) mutable |
| | | { |
| | | MYSQL_RES* result = 0; |
| | | int status = mysql_store_result_cont(&result, m_mysql, mysql_status(flags)); |
| | | if (status) |
| | |
| | | void wait_fetch(int status, MYSQL_RES* result, int field_count, size_t row_count, RowHandler&& row_handler, ResultHandler&& result_handler) |
| | | { |
| | | m_event_handler->set_io_handler(event_flags(status), mysql_get_timeout_value(m_mysql), |
| | | [this, result, field_count, row_count, row_handler, result_handler](int flags) mutable { |
| | | [this, result, field_count, row_count, row_handler, result_handler](int flags) mutable |
| | | { |
| | | MYSQL_ROW row; |
| | | int status = mysql_fetch_row_cont(&row, result, mysql_status(flags)); |
| | | if (status) |
| | |
| | | void wait_free_result(int status, MYSQL_RES* result, size_t row_count, ResultHandler&& handler) NOEXCEPT |
| | | { |
| | | m_event_handler->set_io_handler(event_flags(status), mysql_get_timeout_value(m_mysql), |
| | | [this, result, row_count, handler](int flags) mutable { |
| | | [this, result, row_count, handler](int flags) mutable |
| | | { |
| | | MYSQL* ret = nullptr; |
| | | int status = mysql_free_result_cont(result, mysql_status(flags)); |
| | | if (status) |
| | |
| | | handler(mysql::error(), row_count); |
| | | }); |
| | | } |
| | | |
| | | }; |
| | | |
| | | inline async_statement::async_statement(async_connection& db) |
| | |
| | | { |
| | | const char* errmsg=stmt.errmsg(); |
| | | m_error=stmt.error(); |
| | | if(errmsg) m_errmsg=errmsg; |
| | | if (errmsg) |
| | | m_errmsg = errmsg; |
| | | } |
| | | |
| | | inline error::error(const basic_database& db) |
| | | { |
| | | const char* errmsg=db.errmsg(); |
| | | m_error=db.error(); |
| | | if(errmsg) m_errmsg=errmsg; |
| | | if (errmsg) |
| | | m_errmsg = errmsg; |
| | | } |
| | | |
| | | inline base_statement::base_statement(basic_database& db) |
| | |
| | | class async_pool : public qtl::async_pool<async_pool<EventLoop>, EventLoop, async_connection> |
| | | { |
| | | typedef qtl::async_pool<async_pool<EventLoop>, EventLoop, async_connection> base_class; |
| | | |
| | | public: |
| | | async_pool(EventLoop& ev) : base_class(ev), m_port(0) { } |
| | | virtual ~async_pool() { } |
| | |
| | | void new_connection(EventLoop& ev, Handler&& handler) throw() |
| | | { |
| | | async_connection* db = new async_connection; |
| | | db->open(ev, [this, handler, db](const mysql::error& e) mutable { |
| | | db->open(ev, [this, handler, db](const mysql::error &e) mutable |
| | | { |
| | | if (e) |
| | | { |
| | | delete db; |
| | |
| | | { |
| | | db->charset_name("utf8"); |
| | | } |
| | | handler(e, db); |
| | | }, m_host.data(), m_user.data(), m_password.data(), m_database.data(), 0, m_port); |
| | | handler(e, db); }, m_host.data(), m_user.data(), m_password.data(), m_database.data(), 0, m_port); |
| | | } |
| | | |
| | | protected: |
| | |
| | | #define QTL_ODBC_ENABLE_ASYNC_MODE 1 |
| | | #endif //ODBC 3.80 && Windows |
| | | |
| | | |
| | | #include "qtl_common.hpp" |
| | | #include "qtl_async.hpp" |
| | | |
| | |
| | | namespace odbc |
| | | { |
| | | |
| | | template<SQLSMALLINT> class object; |
| | | template <SQLSMALLINT> |
| | | class object; |
| | | class base_database; |
| | | |
| | | class error : public std::exception |
| | |
| | | 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; |
| | |
| | | class object |
| | | { |
| | | public: |
| | | enum { handler_type=Type }; |
| | | enum |
| | | { |
| | | handler_type = Type |
| | | }; |
| | | object() : m_handle(SQL_NULL_HANDLE) { }; |
| | | object(const object&) = delete; |
| | | object(object&& src) : m_handle(src.m_handle) |
| | |
| | | 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; |
| | | count = (indicator > count) || (indicator == SQL_NO_TOTAL) ? count : indicator; |
| | | m_stmt->verify_error(ret); |
| | | return true; |
| | | } |
| | | else return false; |
| | | else |
| | | return false; |
| | | } |
| | | |
| | | virtual void write_blob(const char* buffer, size_t count) override |
| | |
| | | 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); |
| | | 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); |
| | | 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)); |
| | | } |
| | |
| | | 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) { |
| | | m_params[index].m_after_fetch = [this, &s](const param_data &p) |
| | | { |
| | | SQLLEN readed=SQL_NULL_DATA; |
| | | while(!s.eof() && !s.fail()) |
| | | { |
| | |
| | | m_params[index].m_indicator = SQL_LEN_DATA_AT_EXEC(m_params[index].m_size); |
| | | verify_error(SQLBindParameter(m_handle, static_cast<SQLSMALLINT>(index + 1), SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, |
| | | INT_MAX, 0, &m_params[index], 0, &m_params[index].m_indicator)); |
| | | m_params[index].m_after_fetch = [this, index, ¶m](const param_data& b) { |
| | | m_params[index].m_after_fetch = [this, index, ¶m](const param_data &b) |
| | | { |
| | | blobbuf buf; |
| | | buf.open(this, static_cast<SQLSMALLINT>(index), std::ios::out); |
| | | std::ostream s(&buf); |
| | |
| | | { |
| | | m_params[index].m_data=v; |
| | | m_params[index].m_size=n; |
| | | m_params[index].m_after_fetch=[](const param_data& p) { |
| | | 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 |
| | |
| | | { |
| | | m_params[index].m_data=v; |
| | | m_params[index].m_size=n; |
| | | m_params[index].m_after_fetch=[](const param_data& p) { |
| | | 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 |
| | |
| | | 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 { |
| | | m_params[index].m_after_fetch = [v](const param_data &p) mutable |
| | | { |
| | | if(p.m_indicator==SQL_NULL_DATA) |
| | | v.clear(); |
| | | else |
| | |
| | | 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) { |
| | | 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; |
| | | 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)); |
| | |
| | | { |
| | | 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) { |
| | | m_params[index].m_after_fetch = [this, index, &value](const param_data &p) |
| | | { |
| | | value.open(this, static_cast<SQLSMALLINT>(index), std::ios::in); |
| | | }; |
| | | } |
| | |
| | | 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) { |
| | | param.m_after_fetch = [fetch_fun, &value](const param_data &p) |
| | | { |
| | | value.is_truncated=false; |
| | | if(p.m_indicator==SQL_NULL_DATA) |
| | | { |
| | |
| | | if(p.m_size>0 && p.m_indicator>=p.m_size) |
| | | value.is_truncated=true; |
| | | } |
| | | if(fetch_fun) fetch_fun(p); |
| | | if (fetch_fun) |
| | | fetch_fun(p); |
| | | }; |
| | | } |
| | | |
| | |
| | | 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); |
| | | 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(); |
| | | }; |
| | |
| | | } |
| | | 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); |
| | | 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(); |
| | | }; |
| | |
| | | { |
| | | open(query_text.data(), query_text.size()); |
| | | } |
| | | |
| | | |
| | | template<typename Types> |
| | | void execute(const Types& params) |
| | |
| | | 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(); |
| | | 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; |
| | |
| | | { |
| | | m_connection.resize(512); |
| | | SQLSMALLINT out_len=0; |
| | | if (m_opened) close(); |
| | | 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); |
| | |
| | | SQLSMALLINT length = 0; |
| | | SQLRETURN ret = SQL_SUCCESS; |
| | | std::string input_text; |
| | | if (m_opened) close(); |
| | | if (m_opened) |
| | | close(); |
| | | if (text_length == SQL_NTS) |
| | | input_text = connection_text; |
| | | else |
| | |
| | | //async_connection async_mode(); |
| | | |
| | | #endif //ODBC 3.80 |
| | | |
| | | }; |
| | | |
| | | struct date : public SQL_DATE_STRUCT |
| | |
| | | template<typename Handler> |
| | | void open(Handler&& handler, const char *query_text, size_t text_length = 0) |
| | | { |
| | | if (text_length == 0) text_length = strlen(query_text); |
| | | if (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)); |
| | |
| | | if (m_nQueryTimeout == 0) |
| | | m_nQueryTimeout = query_timeout(); |
| | | ret = SQLExecute(m_handle); |
| | | async_wait(ret, [this, count, handler](const error& e) mutable { |
| | | 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); |
| | | }); |
| | | handler(error(*this, ret), 0); }); |
| | | } |
| | | |
| | | template<typename Types, 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 { |
| | | 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) |
| | | { |
| | |
| | | finish_handler(error()); |
| | | else |
| | | finish_handler(e); |
| | | } |
| | | }); |
| | | } }); |
| | | } |
| | | |
| | | template<typename Handler> |
| | |
| | | SQLRETURN ret; |
| | | m_binded_cols = false; |
| | | ret = SQLMoreResults(m_handle); |
| | | async_wait(ret, [this, handler](const error& e) mutable { |
| | | async_wait(ret, [this, handler](const error &e) mutable |
| | | { |
| | | SQLINTEGER ret=e.code(); |
| | | SQLSMALLINT count = 0; |
| | | if (ret == SQL_ERROR || ret == SQL_INVALID_HANDLE) |
| | |
| | | if (count > 0) |
| | | handler(error()); |
| | | else |
| | | next_result(handler); |
| | | }); |
| | | next_result(handler); }); |
| | | } |
| | | |
| | | HANDLE event_handle() const { return m_hCompleteEvent; } |
| | |
| | | } |
| | | |
| | | private: |
| | | |
| | | void close_event() |
| | | { |
| | | if (m_hCompleteEvent) |
| | |
| | | if(is_still_executing(ret)) |
| | | { |
| | | m_event->set_io_handler(0, m_nQueryTimeout, |
| | | [this, handler](int flags) mutable { |
| | | [this, handler](int flags) mutable |
| | | { |
| | | RETCODE code; |
| | | SQLCompleteAsync(SQL_HANDLE_STMT, m_handle, &code); |
| | | if (SQL_SUCCEEDED(code)) |
| | |
| | | { |
| | | SQLPOINTER token; |
| | | SQLRETURN ret = SQLParamData(m_handle, &token); |
| | | async_wait(ret, [this, index, count, token, handler](const error& e) mutable { |
| | | async_wait(ret, [this, index, count, token, handler](const error &e) mutable |
| | | { |
| | | SQLINTEGER ret = e.code(); |
| | | if (ret == SQL_NEED_DATA) |
| | | { |
| | |
| | | else |
| | | { |
| | | handler(error(*this, ret), affetced_rows()); |
| | | } |
| | | }); |
| | | } }); |
| | | } |
| | | |
| | | int query_timeout() const |
| | |
| | | } |
| | | set_attribute(SQL_ATTR_ASYNC_DBC_EVENT, m_hCompleteEvent); |
| | | } |
| | | async_connection(async_connection&& src) : |
| | | base_database(std::move(src)), |
| | | 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)) |
| | | { |
| | |
| | | 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(); |
| | | 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(); |
| | | 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)); |
| | | } |
| | |
| | | { |
| | | SQLRETURN ret = SQLDisconnect(m_handle); |
| | | m_opened = false; |
| | | async_wait(ret, [this, handler](const error& e) { |
| | | async_wait(ret, [this, handler](const error &e) |
| | | { |
| | | if (!e) m_opened = false; |
| | | handler(e); |
| | | }); |
| | | handler(e); }); |
| | | } |
| | | |
| | | /* |
| | |
| | | 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); |
| | | stmt->open([stmt, handler](const odbc::error &e) mutable |
| | | { handler(e, stmt); }, query_text, text_length); |
| | | } |
| | | |
| | | HANDLE event_handle() const { return m_hCompleteEvent; } |
| | |
| | | } |
| | | |
| | | 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 { |
| | | [this, handler](int flags) mutable |
| | | { |
| | | RETCODE code; |
| | | SQLCompleteAsync(SQL_HANDLE_DBC, m_handle, &code); |
| | | if (SQL_SUCCEEDED(code)) |
| | |
| | | void async_wait_connect(SQLRETURN err, EventLoop& ev, Handler&& handler) |
| | | { |
| | | bind(ev); |
| | | m_BindFunc = [&ev](HANDLE hEvent) { |
| | | m_BindFunc = [&ev](HANDLE hEvent) |
| | | { |
| | | return ev.add(hEvent); |
| | | }; |
| | | if(is_still_executing(err)) |
| | | { |
| | | async_wait(err, [this, handler](const error& e) mutable { |
| | | async_wait(err, [this, handler](const error &e) mutable |
| | | { |
| | | if (!e) m_opened = true; |
| | | handler(e); |
| | | }); |
| | | handler(e); }); |
| | | } |
| | | else |
| | | { |
| | |
| | | |
| | | 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 }; |
| | | enum |
| | | { |
| | | part_name, |
| | | part_prompt, |
| | | part_list, |
| | | part_value |
| | | }; |
| | | const char* sp=output_text; |
| | | const char* token=sp; |
| | | connection_parameter parameter; |
| | |
| | | part_type=part_list; |
| | | parameter.m_value_list.clear(); |
| | | token=sp+1; |
| | | break;; |
| | | break; |
| | | ; |
| | | case '}': |
| | | case ',': |
| | | if(part_type==part_list) |
| | |
| | | else |
| | | { |
| | | oss<<"UID="<<user<<";PWD="; |
| | | if(password) oss<<password; |
| | | if (password) |
| | | oss << password; |
| | | oss<<";Trusted_Connection=no;"; |
| | | } |
| | | oss<<"DATABASE="<<db; |
| | |
| | | else |
| | | { |
| | | oss << "UID=" << user << ";PWD="; |
| | | if (password) oss << password; |
| | | if (password) |
| | | oss << password; |
| | | oss << ";Trusted_Connection=no;"; |
| | | } |
| | | oss << "DATABASE=" << db; |
| | | odbc::async_connection::open(ev, handler, oss.str()); |
| | | } |
| | | |
| | | }; |
| | | |
| | | #endif |
| | |
| | | { |
| | | std::ostringstream oss; |
| | | oss<<"DRIVER={Microsoft Access Driver};DBQ="<<filename; |
| | | if(user) oss<<";UID:"<<user; |
| | | if(password) oss<<";PWD="<<password; |
| | | if (user) |
| | | oss << ";UID:" << user; |
| | | if (password) |
| | | oss << ";PWD=" << password; |
| | | odbc::database::open(oss.str()); |
| | | } |
| | | }; |
| | |
| | | class async_pool : public qtl::async_pool<async_pool<EventLoop>, EventLoop, async_connection> |
| | | { |
| | | typedef qtl::async_pool<async_pool<EventLoop>, EventLoop, async_connection> base_class; |
| | | |
| | | public: |
| | | async_pool(EventLoop& ev) : base_class(ev) { } |
| | | virtual ~async_pool() { } |
| | |
| | | void new_connection(EventLoop& ev, Handler&& handler) throw() |
| | | { |
| | | async_connection* db = new async_connection(env); |
| | | db->open(ev, [this, handler, db](const mysql::error& e) mutable { |
| | | db->open(ev, [this, handler, db](const mysql::error &e) mutable |
| | | { |
| | | if (e) |
| | | { |
| | | delete db; |
| | | db = nullptr; |
| | | } |
| | | handler(e, db); |
| | | }, m_connection); |
| | | handler(e, db); }, m_connection); |
| | | } |
| | | |
| | | protected: |
| | |
| | | #include <catalog/pg_type.h> |
| | | } |
| | | |
| | | |
| | | #ifdef open |
| | | #undef open |
| | | #endif //open |
| | |
| | | //PQsetErrorVerbosity(conn, verbosity); |
| | | //PQsetErrorContextVisibility(conn, show_context); |
| | | const char* errmsg = PQerrorMessage(conn); |
| | | if (errmsg) m_errmsg = errmsg; |
| | | else m_errmsg.clear(); |
| | | if (errmsg) |
| | | m_errmsg = errmsg; |
| | | else |
| | | m_errmsg.clear(); |
| | | } |
| | | |
| | | explicit error(PGresult* res) |
| | | { |
| | | const char* errmsg = PQresultErrorMessage(res); |
| | | if (errmsg) m_errmsg = errmsg; |
| | | else m_errmsg.clear(); |
| | | if (errmsg) |
| | | m_errmsg = errmsg; |
| | | else |
| | | m_errmsg.clear(); |
| | | } |
| | | |
| | | explicit error(const char* errmsg) : m_errmsg(errmsg) { } |
| | |
| | | result -= b; |
| | | return result; |
| | | } |
| | | |
| | | |
| | | struct timestamptz |
| | | { |
| | |
| | | } |
| | | |
| | | protected: |
| | | enum { default_buffer_size = 4096 }; |
| | | enum |
| | | { |
| | | default_buffer_size = 4096 |
| | | }; |
| | | |
| | | virtual bool read_blob(char* buffer, off_type& count, pos_type position) override |
| | | { |
| | |
| | | int32_t ndim; |
| | | int32_t flags; |
| | | int32_t elemtype; |
| | | struct dimension { |
| | | struct dimension |
| | | { |
| | | int32_t length; |
| | | int32_t lower_bound; |
| | | } dims[1]; |
| | |
| | | struct base_object_traits |
| | | { |
| | | typedef T value_type; |
| | | enum { type_id = id }; |
| | | enum |
| | | { |
| | | type_id = id |
| | | }; |
| | | static bool is_match(Oid v) |
| | | { |
| | | return v == type_id; |
| | |
| | | struct object_traits; |
| | | |
| | | #define QTL_POSTGRES_SIMPLE_TRAITS(T, oid, array_oid) \ |
| | | template<> struct object_traits<T> : public base_object_traits<T, oid> { \ |
| | | enum { array_type_id = array_oid }; \ |
| | | template <> \ |
| | | struct object_traits<T> : public base_object_traits<T, oid> \ |
| | | { \ |
| | | enum \ |
| | | { \ |
| | | array_type_id = array_oid \ |
| | | }; \ |
| | | static const char* get(value_type& result, const char* data, const char* end) \ |
| | | { \ |
| | | result = *reinterpret_cast<const value_type*>(data); \ |
| | | return data+sizeof(value_type); \ |
| | | } \ |
| | | static std::pair<const char*, size_t> data(const T& v, std::vector<char>& /*data*/) { \ |
| | | static std::pair<const char *, size_t> data(const T &v, std::vector<char> & /*data*/) \ |
| | | { \ |
| | | return std::make_pair(reinterpret_cast<const char*>(&v), sizeof(T)); \ |
| | | } \ |
| | | }; |
| | |
| | | template<typename T, Oid id, Oid array_id> |
| | | struct integral_traits : public base_object_traits<T, id> |
| | | { |
| | | enum { array_type_id = array_id }; |
| | | enum |
| | | { |
| | | array_type_id = array_id |
| | | }; |
| | | typedef typename base_object_traits<T, id>::value_type value_type; |
| | | static const char* get(value_type& v, const char* data, const char* end) |
| | | { |
| | |
| | | } |
| | | }; |
| | | |
| | | template<> struct object_traits<int16_t> : public integral_traits<int16_t, INT2OID, INT2ARRAYOID> |
| | | template <> |
| | | struct object_traits<int16_t> : public integral_traits<int16_t, INT2OID, INT2ARRAYOID> |
| | | { |
| | | }; |
| | | |
| | | template<> struct object_traits<int32_t> : public integral_traits<int32_t, INT4OID, INT4ARRAYOID> |
| | | template <> |
| | | struct object_traits<int32_t> : public integral_traits<int32_t, INT4OID, INT4ARRAYOID> |
| | | { |
| | | }; |
| | | |
| | | template<> struct object_traits<int64_t> : public integral_traits<int64_t, INT8OID, 1016> |
| | | template <> |
| | | struct object_traits<int64_t> : public integral_traits<int64_t, INT8OID, 1016> |
| | | { |
| | | }; |
| | | |
| | | template<> struct object_traits<Oid> : public integral_traits<Oid, OIDOID, OIDARRAYOID> |
| | | template <> |
| | | struct object_traits<Oid> : public integral_traits<Oid, OIDOID, OIDARRAYOID> |
| | | { |
| | | }; |
| | | |
| | | template<typename T> |
| | | struct text_traits : public base_object_traits<T, TEXTOID> |
| | | { |
| | | enum { array_type_id = TEXTARRAYOID }; |
| | | enum |
| | | { |
| | | array_type_id = TEXTARRAYOID |
| | | }; |
| | | }; |
| | | |
| | | template<> struct object_traits<const char*> : public text_traits<const char*> |
| | | template <> |
| | | struct object_traits<const char *> : public text_traits<const char *> |
| | | { |
| | | static bool is_match(Oid v) |
| | | { |
| | |
| | | } |
| | | }; |
| | | |
| | | template<> struct object_traits<char*> : public object_traits<const char*> |
| | | template <> |
| | | struct object_traits<char *> : public object_traits<const char *> |
| | | { |
| | | }; |
| | | |
| | | template<> struct object_traits<std::string> : public text_traits<std::string> |
| | | template <> |
| | | struct object_traits<std::string> : public text_traits<std::string> |
| | | { |
| | | static bool is_match(Oid v) |
| | | { |
| | |
| | | } |
| | | }; |
| | | |
| | | template<> struct object_traits<timestamp> : public base_object_traits<timestamp, TIMESTAMPOID> |
| | | template <> |
| | | struct object_traits<timestamp> : public base_object_traits<timestamp, TIMESTAMPOID> |
| | | { |
| | | enum { array_type_id = TIMESTAMPOID+1 }; |
| | | enum |
| | | { |
| | | array_type_id = TIMESTAMPOID + 1 |
| | | }; |
| | | static const char* get(value_type& result, const char* data, const char* end) |
| | | { |
| | | result = *reinterpret_cast<const timestamp*>(data); |
| | |
| | | } |
| | | }; |
| | | |
| | | template<> struct object_traits<timestamptz> : public base_object_traits<timestamptz, TIMESTAMPTZOID> |
| | | template <> |
| | | struct object_traits<timestamptz> : public base_object_traits<timestamptz, TIMESTAMPTZOID> |
| | | { |
| | | enum { array_type_id = TIMESTAMPTZOID+1 }; |
| | | enum |
| | | { |
| | | array_type_id = TIMESTAMPTZOID + 1 |
| | | }; |
| | | static const char* get(value_type& result, const char* data, const char* end) |
| | | { |
| | | result = *reinterpret_cast<const timestamptz*>(data); |
| | |
| | | } |
| | | }; |
| | | |
| | | template<> struct object_traits<interval> : public base_object_traits<interval, INTERVALOID> |
| | | template <> |
| | | struct object_traits<interval> : public base_object_traits<interval, INTERVALOID> |
| | | { |
| | | enum { array_type_id = INTERVALOID+1 }; |
| | | enum |
| | | { |
| | | array_type_id = INTERVALOID + 1 |
| | | }; |
| | | static const char* get(value_type& result, const char* data, const char* end) |
| | | { |
| | | const ::interval* value = reinterpret_cast<const ::interval*>(data); |
| | |
| | | } |
| | | }; |
| | | |
| | | template<> struct object_traits<date> : public base_object_traits<date, DATEOID> |
| | | template <> |
| | | struct object_traits<date> : public base_object_traits<date, DATEOID> |
| | | { |
| | | enum { array_type_id = 1182 }; |
| | | enum |
| | | { |
| | | array_type_id = 1182 |
| | | }; |
| | | static const char* get(value_type& result, const char* data, const char* end) |
| | | { |
| | | result = *reinterpret_cast<const date*>(data); |
| | |
| | | template<typename T> |
| | | struct bytea_traits : public base_object_traits<T, BYTEAOID> |
| | | { |
| | | enum { array_type_id = 1001 }; |
| | | enum |
| | | { |
| | | array_type_id = 1001 |
| | | }; |
| | | }; |
| | | |
| | | template<> struct object_traits<qtl::const_blob_data> : public bytea_traits<qtl::const_blob_data> |
| | | template <> |
| | | struct object_traits<qtl::const_blob_data> : public bytea_traits<qtl::const_blob_data> |
| | | { |
| | | static const char* get(value_type& result, const char* data, const char* end) |
| | | { |
| | |
| | | } |
| | | }; |
| | | |
| | | template<> struct object_traits<qtl::blob_data> : public bytea_traits<qtl::blob_data> |
| | | template <> |
| | | struct object_traits<qtl::blob_data> : public bytea_traits<qtl::blob_data> |
| | | { |
| | | static const char* get(qtl::blob_data& value, const char* data, const char* end) |
| | | { |
| | |
| | | } |
| | | }; |
| | | |
| | | template<> struct object_traits<std::vector<uint8_t>> : public bytea_traits<std::vector<uint8_t>> |
| | | template <> |
| | | struct object_traits<std::vector<uint8_t>> : public bytea_traits<std::vector<uint8_t>> |
| | | { |
| | | static const char* get(value_type& result, const char* data, const char* end) |
| | | { |
| | |
| | | } |
| | | }; |
| | | |
| | | template<> struct object_traits<large_object> : public base_object_traits<large_object, OIDOID> |
| | | template <> |
| | | struct object_traits<large_object> : public base_object_traits<large_object, OIDOID> |
| | | { |
| | | enum { array_type_id = OIDARRAYOID }; |
| | | enum |
| | | { |
| | | array_type_id = OIDARRAYOID |
| | | }; |
| | | static value_type get(PGconn* conn, const char* data, const char* end) |
| | | { |
| | | int32_t oid; |
| | |
| | | }; |
| | | |
| | | template<typename Iterator> |
| | | struct object_traits<std::pair<typename std::enable_if<std::is_object<typename std::iterator_traits<Iterator>::value_type>::value, Iterator>::type, Iterator>> : |
| | | public range_traits<Iterator, object_traits<typename std::iterator_traits<Iterator>::value_type>::array_type_id> |
| | | struct object_traits<std::pair<typename std::enable_if<std::is_object<typename std::iterator_traits<Iterator>::value_type>::value, Iterator>::type, Iterator>> : public range_traits<Iterator, object_traits<typename std::iterator_traits<Iterator>::value_type>::array_type_id> |
| | | { |
| | | }; |
| | | |
| | |
| | | } |
| | | }; |
| | | |
| | | template<typename T, size_t N> struct object_traits<T (&)[N]> : public carray_traits<T, N, object_traits<T>::array_type_id> |
| | | template <typename T, size_t N> |
| | | struct object_traits<T (&)[N]> : public carray_traits<T, N, object_traits<T>::array_type_id> |
| | | { |
| | | }; |
| | | |
| | | template<typename T, size_t N> struct object_traits<std::array<T, N>> : public array_traits<T, N, object_traits<T>::array_type_id> |
| | | template <typename T, size_t N> |
| | | struct object_traits<std::array<T, N>> : public array_traits<T, N, object_traits<T>::array_type_id> |
| | | { |
| | | }; |
| | | |
| | |
| | | void bind(const char* data, size_t length=0) |
| | | { |
| | | m_value = data; |
| | | if(length>0) m_length = length; |
| | | else m_length = strlen(data); |
| | | if (length > 0) |
| | | m_length = length; |
| | | else |
| | | m_length = strlen(data); |
| | | } |
| | | template<typename T, size_t N> |
| | | void bind(const T(&v)[N]) |
| | |
| | | class base_statement |
| | | { |
| | | friend class error; |
| | | |
| | | public: |
| | | explicit base_statement(base_database& db); |
| | | ~base_statement() |
| | |
| | | { |
| | | auto binder_list = make_binder_list(Types()...); |
| | | std::array<Oid, sizeof...(Types)> types; |
| | | std::transform(binder_list.begin(), binder_list.end(), types.begin(), [](const binder& b) { |
| | | return b.type(); |
| | | }); |
| | | std::transform(binder_list.begin(), binder_list.end(), types.begin(), [](const binder &b) |
| | | { return b.type(); }); |
| | | |
| | | open(command, types.size(), types.data()); |
| | | } |
| | |
| | | void simple_execute(const char* query_text, uint64_t* paffected = nullptr) |
| | | { |
| | | qtl::postgres::result res(PQexec(m_conn, query_text)); |
| | | if (!res) throw_exception(); |
| | | if (!res) |
| | | throw_exception(); |
| | | res.verify_error<PGRES_COMMAND_OK, PGRES_TUPLES_OK>(); |
| | | if (paffected) *paffected = res.affected_rows(); |
| | | if (paffected) |
| | | *paffected = res.affected_rows(); |
| | | } |
| | | template<typename ValueProc> |
| | | void simple_query(const char* query_text, ValueProc&& proc) |
| | | { |
| | | qtl::postgres::result res(PQexec(m_conn, query_text)); |
| | | if (!res) throw_exception(); |
| | | if (!res) |
| | | throw_exception(); |
| | | res.verify_error<PGRES_COMMAND_OK, PGRES_TUPLES_OK>(); |
| | | if (res.status() == PGRES_TUPLES_OK) |
| | | { |
| | |
| | | qtl::postgres::result res(PQexec(m_conn, "")); |
| | | return res && res.status() == PGRES_COMMAND_OK; |
| | | } |
| | | |
| | | }; |
| | | |
| | | inline int event_flags(PostgresPollingStatusType status) |
| | |
| | | if (flushed == 1) |
| | | { |
| | | event->set_io_handler(qtl::event::ef_read | qtl::event::ef_write, timeout, |
| | | [event, conn, timeout, handler](int flags) mutable { |
| | | [event, conn, timeout, handler](int flags) mutable |
| | | { |
| | | if (flags&qtl::event::ef_timeout) |
| | | { |
| | | handler(postgres::timeout()); |
| | |
| | | else |
| | | { |
| | | event->set_io_handler(qtl::event::ef_read, 10, |
| | | [event, conn, timeout, handler](int flags) mutable { |
| | | [event, conn, timeout, handler](int flags) mutable |
| | | { |
| | | if (flags&qtl::event::ef_timeout) |
| | | { |
| | | handler(postgres::timeout()); |
| | |
| | | std::transform(_name.begin(), _name.end(), _name.begin(), tolower); |
| | | if (PQsendPrepare(m_conn, _name.data(), command, nParams, paramTypes)) |
| | | { |
| | | async_wait([this, handler](error e) mutable { |
| | | async_wait([this, handler](error e) mutable |
| | | { |
| | | if (!e) |
| | | { |
| | | m_res = PQgetResult(m_conn); |
| | |
| | | m_res = PQgetResult(m_conn); |
| | | } |
| | | } |
| | | handler(e); |
| | | }); |
| | | handler(e); }); |
| | | } |
| | | else |
| | | { |
| | |
| | | { |
| | | auto binder_list = make_binder_list(Types()...); |
| | | std::array<Oid, sizeof...(Types)> types; |
| | | std::transform(binder_list.begin(), binder_list.end(), types.begin(), [](const binder& b) { |
| | | return b.type(); |
| | | }); |
| | | std::transform(binder_list.begin(), binder_list.end(), types.begin(), [](const binder &b) |
| | | { return b.type(); }); |
| | | |
| | | open(std::forward<Handler>(handler), command, types.size(), types.data()); |
| | | } |
| | |
| | | error e; |
| | | res.verify_error<PGRES_COMMAND_OK, PGRES_TUPLES_OK>(e); |
| | | finish(res); |
| | | if(e) throw e; |
| | | if (e) |
| | | throw e; |
| | | } |
| | | base_statement::close(); |
| | | } |
| | |
| | | { |
| | | if(PQisBusy(m_conn)) |
| | | { |
| | | async_wait([this, handler](const error& e) mutable { |
| | | close(handler); |
| | | }); |
| | | async_wait([this, handler](const error &e) mutable |
| | | { close(handler); }); |
| | | } |
| | | else |
| | | { |
| | |
| | | bool ok = PQsendQuery(m_conn, oss.str().data()); |
| | | if (ok) |
| | | { |
| | | async_wait([this, handler](postgres::error e) mutable { |
| | | async_wait([this, handler](postgres::error e) mutable |
| | | { |
| | | if (PQstatus(m_conn) == CONNECTION_OK) |
| | | { |
| | | result res(PQgetResult(m_conn)); |
| | |
| | | { |
| | | _name.clear(); |
| | | handler(error()); |
| | | } |
| | | }); |
| | | } }); |
| | | } |
| | | else |
| | | { |
| | |
| | | if (PQsendQueryPrepared(m_conn, _name.data(), 0, nullptr, nullptr, nullptr, 1) && |
| | | PQsetSingleRowMode(m_conn)) |
| | | { |
| | | async_wait([this, handler](error e) { |
| | | async_wait([this, handler](error e) |
| | | { |
| | | if (!e) |
| | | { |
| | | m_res = PQgetResult(m_conn); |
| | | m_res.verify_error<PGRES_COMMAND_OK, PGRES_SINGLE_TUPLE>(e); |
| | | finish(m_res); |
| | | } |
| | | handler(e); |
| | | }); |
| | | handler(e); }); |
| | | } |
| | | else |
| | | { |
| | |
| | | } |
| | | if (PQisBusy(m_conn)) |
| | | { |
| | | async_wait([this, handler](error e) mutable { |
| | | async_wait([this, handler](error e) mutable |
| | | { |
| | | if (!e) |
| | | { |
| | | m_res = PQgetResult(m_conn); |
| | |
| | | else |
| | | { |
| | | handler(e, 0); |
| | | } |
| | | }); |
| | | } }); |
| | | } |
| | | } |
| | | |
| | |
| | | row_handler(); |
| | | if (PQisBusy(m_conn)) |
| | | { |
| | | async_wait([this, &values, row_handler, finish_handler](const error& e) { |
| | | async_wait([this, &values, row_handler, finish_handler](const error &e) |
| | | { |
| | | if (e) |
| | | { |
| | | finish_handler(e); |
| | |
| | | { |
| | | m_res = PQgetResult(m_conn); |
| | | fetch(std::forward<Types>(values), row_handler, finish_handler); |
| | | } |
| | | }); |
| | | } }); |
| | | } |
| | | else |
| | | { |
| | |
| | | template<typename Handler> |
| | | void next_result(Handler&& handler) |
| | | { |
| | | async_wait([this, handler](const error& e) { |
| | | async_wait([this, handler](const error &e) |
| | | { |
| | | if (e) |
| | | { |
| | | handler(e); |
| | |
| | | { |
| | | m_res = PQgetResult(m_conn); |
| | | handler(error()); |
| | | } |
| | | }); |
| | | } }); |
| | | } |
| | | |
| | | private: |
| | |
| | | bool ok = PQsendQuery(m_conn, query_text); |
| | | if (ok) |
| | | { |
| | | async_wait([this, handler](postgres::error e) mutable { |
| | | async_wait([this, handler](postgres::error e) mutable |
| | | { |
| | | result res(PQgetResult(m_conn)); |
| | | res.verify_error<PGRES_COMMAND_OK, PGRES_TUPLES_OK>(e); |
| | | uint64_t affected = res.affected_rows(); |
| | | handler(e, affected); |
| | | while (res) |
| | | res = PQgetResult(m_conn); |
| | | }); |
| | | res = PQgetResult(m_conn); }); |
| | | } |
| | | else |
| | | { |
| | |
| | | bool ok = PQsendQuery(m_conn, query); |
| | | if (ok) |
| | | { |
| | | async_wait([this, row_handler, result_handler](postgres::error e) mutable { |
| | | async_wait([this, row_handler, result_handler](postgres::error e) mutable |
| | | { |
| | | result res(PQgetResult(m_conn)); |
| | | res.verify_error<PGRES_COMMAND_OK, PGRES_TUPLES_OK>(e); |
| | | if (e) |
| | |
| | | stmt.fetch_all(row_handler); |
| | | res = PQgetResult(m_conn); |
| | | } |
| | | result_handler(e, affected); |
| | | }); |
| | | result_handler(e, affected); }); |
| | | } |
| | | else |
| | | { |
| | |
| | | void open_command(const char* query_text, size_t /*text_length*/, Handler&& handler) |
| | | { |
| | | std::shared_ptr<async_statement> stmt = std::make_shared<async_statement>(*this); |
| | | stmt->open([stmt, handler](const postgres::error& e) mutable { |
| | | handler(e, stmt); |
| | | }, query_text, 0); |
| | | stmt->open([stmt, handler](const postgres::error &e) mutable |
| | | { handler(e, stmt); }, query_text, 0); |
| | | } |
| | | |
| | | template<typename Handler> |
| | |
| | | case PGRES_POLLING_READING: |
| | | case PGRES_POLLING_WRITING: |
| | | m_event_handler->set_io_handler(event_flags(status), m_connect_timeout, |
| | | [this, handler](int flags) mutable { |
| | | [this, handler](int flags) mutable |
| | | { |
| | | if (flags&event::ef_timeout) |
| | | { |
| | | handler(postgres::timeout()); |
| | |
| | | case PGRES_POLLING_READING: |
| | | case PGRES_POLLING_WRITING: |
| | | m_event_handler->set_io_handler(event_flags(status), m_connect_timeout, |
| | | [this, handler](int flags) mutable { |
| | | [this, handler](int flags) mutable |
| | | { |
| | | if (flags&event::ef_timeout) |
| | | { |
| | | handler(postgres::timeout()); |
| | |
| | | { |
| | | qtl::postgres::async_wait(event(), m_conn, m_query_timeout, std::forward<Handler>(handler)); |
| | | } |
| | | |
| | | }; |
| | | |
| | | inline async_statement::async_statement(async_connection& db) |
| | |
| | | m_event = db.event(); |
| | | m_timeout = db.query_timeout(); |
| | | } |
| | | |
| | | |
| | | typedef qtl::transaction<database> transaction; |
| | | |
| | |
| | | |
| | | } |
| | | |
| | | |
| | | #endif //_SQL_POSTGRES_H_ |
| | | |
| | |
| | | class async_pool : public qtl::async_pool<async_pool<EventLoop>, EventLoop, async_connection> |
| | | { |
| | | typedef qtl::async_pool<async_pool<EventLoop>, EventLoop, async_connection> base_class; |
| | | |
| | | public: |
| | | async_pool(EventLoop& ev) : base_class(ev) { } |
| | | virtual ~async_pool() { } |
| | |
| | | void new_connection(EventLoop& ev, Handler&& handler) throw() |
| | | { |
| | | async_connection* db = new async_connection; |
| | | db->open(ev, [this, handler, db](const postgres::error& e) mutable { |
| | | db->open(ev, [this, handler, db](const postgres::error &e) mutable |
| | | { |
| | | if (e) |
| | | { |
| | | delete db; |
| | | db = nullptr; |
| | | } |
| | | handler(e, db); |
| | | }, m_params); |
| | | handler(e, db); }, m_params); |
| | | } |
| | | |
| | | protected: |
| | |
| | | m_fetch_result=SQLITE_OK; |
| | | } |
| | | }while(!m_tail_text.empty() && count==0); |
| | | return count>0;; |
| | | return count > 0; |
| | | ; |
| | | } |
| | | |
| | | int affetced_rows() const |
| | |
| | | int m_fetch_result; |
| | | void verify_error(int e) |
| | | { |
| | | if(e!=SQLITE_OK) throw error(e); |
| | | if (e != SQLITE_OK) |
| | | throw error(e); |
| | | } |
| | | }; |
| | | |
| | |
| | | std::ios_base::openmode mode, const char* dbname="main") |
| | | { |
| | | int flags=0; |
| | | if(mode&std::ios_base::out) flags=1; |
| | | if (mode & std::ios_base::out) |
| | | flags = 1; |
| | | if(sqlite3_blob_open(db.handle(), dbname, table, column, row, flags, &m_blob)==SQLITE_OK) |
| | | { |
| | | m_size=sqlite3_blob_bytes(m_blob)/sizeof(char); |
| | |
| | | } |
| | | |
| | | protected: |
| | | enum { default_buffer_size = 4096 }; |
| | | enum |
| | | { |
| | | default_buffer_size = 4096 |
| | | }; |
| | | |
| | | virtual pos_type seekoff( off_type off, std::ios_base::seekdir dir, |
| | | std::ios_base::openmode which = std::ios_base::in | std::ios_base::out ) override |
| | |
| | | eback()[intersection.first-m_inpos]=c; |
| | | } |
| | | m_outpos+=1; |
| | | |
| | | } |
| | | return ch; |
| | | } |
| | | |
| | | virtual int_type pbackfail( int_type c = traits_type::eof() ) override |
| | | { |
| | | if (gptr() == 0 |
| | | || gptr() <= eback() |
| | | || (!traits_type::eq_int_type(traits_type::eof(), c) |
| | | && !traits_type::eq(traits_type::to_char_type(c), gptr()[-1]))) |
| | | if (gptr() == 0 || gptr() <= eback() || (!traits_type::eq_int_type(traits_type::eof(), c) && !traits_type::eq(traits_type::to_char_type(c), gptr()[-1]))) |
| | | { |
| | | return (traits_type::eof()); // can't put back, fail |
| | | } |
| | |
| | | private: |
| | | blobbuf m_buffer; |
| | | }; |
| | | |
| | | |
| | | typedef qtl::transaction<database> transaction; |
| | | |
| | |
| | | } |
| | | |
| | | #endif //_QTL_SQLITE_POOL_H_ |
| | | |