2017-12-16 21:41:46 +01:00
|
|
|
|
#include "ASyncDBConnection.h"
|
2017-08-23 08:10:01 +02:00
|
|
|
|
#include "ScopeGuard.h"
|
2017-01-06 07:23:40 +01:00
|
|
|
|
#include <chrono>
|
2017-01-03 07:22:36 +01:00
|
|
|
|
|
2017-08-24 21:12:32 +02:00
|
|
|
|
using namespace boost::asio;
|
|
|
|
|
|
|
2018-01-08 20:54:03 +01:00
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
|
|
class registerMetaTypes {
|
|
|
|
|
|
public:
|
|
|
|
|
|
registerMetaTypes()
|
|
|
|
|
|
{
|
|
|
|
|
|
qRegisterMetaType<ASyncDBConnection::State>();
|
|
|
|
|
|
qRegisterMetaType<Pgsql::ErrorDetails>();
|
2018-01-09 20:39:43 +01:00
|
|
|
|
qRegisterMetaType<std::shared_ptr<Pgsql::Result>>();
|
|
|
|
|
|
}
|
2018-01-08 20:54:03 +01:00
|
|
|
|
} registerMetaTypes_instance;
|
2017-09-03 14:37:12 +02:00
|
|
|
|
|
|
|
|
|
|
|
2018-01-08 20:54:03 +01:00
|
|
|
|
}
|
2017-09-03 14:37:12 +02:00
|
|
|
|
|
2017-08-24 21:12:32 +02:00
|
|
|
|
ASyncDBConnection::ASyncDBConnection(boost::asio::io_service &ios)
|
|
|
|
|
|
: m_asioSock(ios)
|
2017-08-25 08:37:18 +02:00
|
|
|
|
{}
|
2017-01-03 07:22:36 +01:00
|
|
|
|
|
2017-08-25 08:37:18 +02:00
|
|
|
|
ASyncDBConnection::~ASyncDBConnection() = default;
|
2017-01-03 07:22:36 +01:00
|
|
|
|
|
2017-01-15 21:38:07 +01:00
|
|
|
|
ASyncDBConnection::State ASyncDBConnection::state() const
|
|
|
|
|
|
{
|
2017-08-24 21:12:32 +02:00
|
|
|
|
return m_state;
|
2017-01-15 21:38:07 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-01-15 21:01:40 +01:00
|
|
|
|
void ASyncDBConnection::setupConnection(const ConnectionConfig &config)
|
2017-01-06 07:23:40 +01:00
|
|
|
|
{
|
2017-08-24 21:12:32 +02:00
|
|
|
|
m_config = config;
|
2017-08-23 13:27:23 +02:00
|
|
|
|
auto keywords = m_config.getKeywords();
|
|
|
|
|
|
auto values = m_config.getValues();
|
2017-01-06 07:23:40 +01:00
|
|
|
|
|
2017-08-24 21:12:32 +02:00
|
|
|
|
bool ok = m_connection.connectStart(keywords, values);
|
|
|
|
|
|
// auto start = std::chrono::steady_clock::now();
|
2017-09-02 11:55:47 +02:00
|
|
|
|
if (ok && m_connection.status() != CONNECTION_BAD) {
|
2017-08-24 21:12:32 +02:00
|
|
|
|
auto sock_handle = m_connection.socket();
|
2018-04-08 09:06:05 +02:00
|
|
|
|
|
2017-08-24 21:12:32 +02:00
|
|
|
|
m_asioSock.assign(ip::tcp::v4(), sock_handle);
|
|
|
|
|
|
m_asioSock.non_blocking(true);
|
|
|
|
|
|
|
|
|
|
|
|
m_asioSock.async_write_some(null_buffers(),
|
|
|
|
|
|
[this] (boost::system::error_code ec, std::size_t s)
|
|
|
|
|
|
{ async_connect_handler(ec, s); }
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
2017-01-06 07:23:40 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-12-16 21:41:46 +01:00
|
|
|
|
void ASyncDBConnection::async_connect_handler(boost::system::error_code ec, std::size_t /*s*/)
|
2017-01-06 07:23:40 +01:00
|
|
|
|
{
|
2017-08-25 08:37:18 +02:00
|
|
|
|
// boost::asio::error::operation_aborted
|
|
|
|
|
|
if (ec == boost::system::errc::success) {
|
|
|
|
|
|
auto poll_state = m_connection.connectPoll();
|
|
|
|
|
|
if (poll_state == PGRES_POLLING_OK) {
|
|
|
|
|
|
// if connected return true
|
|
|
|
|
|
doStateCallback(State::Connected);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (poll_state == PGRES_POLLING_FAILED) {
|
|
|
|
|
|
doStateCallback(State::NotConnected);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (poll_state == PGRES_POLLING_READING) {
|
|
|
|
|
|
doStateCallback(State::Connecting);
|
|
|
|
|
|
m_asioSock.async_read_some(null_buffers(),
|
|
|
|
|
|
[this] (boost::system::error_code ec, std::size_t s)
|
|
|
|
|
|
{ async_connect_handler(ec, s); }
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (poll_state == PGRES_POLLING_WRITING) {
|
|
|
|
|
|
doStateCallback(State::Connecting);
|
|
|
|
|
|
m_asioSock.async_write_some(null_buffers(),
|
|
|
|
|
|
[this] (boost::system::error_code ec, std::size_t s)
|
|
|
|
|
|
{ async_connect_handler(ec, s); }
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
2017-08-24 21:12:32 +02:00
|
|
|
|
}
|
2017-01-06 07:23:40 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-10-05 16:02:06 +02:00
|
|
|
|
|
2017-08-24 21:12:32 +02:00
|
|
|
|
void ASyncDBConnection::doStateCallback(State state)
|
2017-01-06 07:23:40 +01:00
|
|
|
|
{
|
2017-09-02 11:55:47 +02:00
|
|
|
|
m_state = state;
|
2017-08-24 21:12:32 +02:00
|
|
|
|
if (state == State::Connected) {
|
2017-08-25 08:37:18 +02:00
|
|
|
|
m_canceller = m_connection.getCancel();
|
2017-08-24 21:12:32 +02:00
|
|
|
|
m_connection.setNoticeReceiver(
|
|
|
|
|
|
[this](const PGresult *result) { processNotice(result); });
|
|
|
|
|
|
}
|
2018-01-08 20:54:03 +01:00
|
|
|
|
emit onStateChanged(state);
|
2017-10-05 16:02:06 +02:00
|
|
|
|
}
|
2017-01-08 09:58:34 +01:00
|
|
|
|
|
|
|
|
|
|
|
2017-08-24 21:12:32 +02:00
|
|
|
|
void ASyncDBConnection::closeConnection()
|
|
|
|
|
|
{
|
|
|
|
|
|
// SHould this be async too????
|
2017-08-25 08:37:18 +02:00
|
|
|
|
if (m_state == State::QuerySend) {
|
|
|
|
|
|
m_canceller.cancel(nullptr);
|
|
|
|
|
|
}
|
2017-09-02 11:55:47 +02:00
|
|
|
|
if (m_state != State::NotConnected) {
|
2018-04-08 09:06:05 +02:00
|
|
|
|
// Do not really want to close it before libpq is finished with it
|
|
|
|
|
|
// However explicitly is the destroctor doing the right thing?
|
|
|
|
|
|
//m_asioSock.close();
|
2017-09-02 11:55:47 +02:00
|
|
|
|
m_connection.close();
|
|
|
|
|
|
}
|
2017-08-25 08:37:18 +02:00
|
|
|
|
doStateCallback(State::NotConnected);
|
2017-01-08 09:58:34 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-08-24 21:12:32 +02:00
|
|
|
|
bool ASyncDBConnection::send(const std::string &command, on_result_callback on_result)
|
2017-01-08 09:58:34 +01:00
|
|
|
|
{
|
2017-08-24 21:12:32 +02:00
|
|
|
|
m_connection.sendQuery(command);
|
|
|
|
|
|
m_timer.start();
|
|
|
|
|
|
doStateCallback(State::QuerySend);
|
|
|
|
|
|
m_asioSock.async_read_some(null_buffers(),
|
|
|
|
|
|
[this, on_result] (boost::system::error_code ec, std::size_t s)
|
|
|
|
|
|
{ async_query_handler(ec, s, on_result); }
|
|
|
|
|
|
);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
2017-02-19 11:12:43 +01:00
|
|
|
|
|
2017-08-24 21:12:32 +02:00
|
|
|
|
bool ASyncDBConnection::send(const std::string &command, Pgsql::Params params, on_result_callback on_result)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_connection.sendQueryParams(command.c_str(), params);
|
|
|
|
|
|
m_timer.start();
|
|
|
|
|
|
doStateCallback(State::QuerySend);
|
|
|
|
|
|
m_asioSock.async_read_some(null_buffers(),
|
|
|
|
|
|
[this, on_result] (boost::system::error_code ec, std::size_t s)
|
|
|
|
|
|
{ async_query_handler(ec, s, on_result); }
|
|
|
|
|
|
);
|
|
|
|
|
|
return true;
|
2017-01-08 09:58:34 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-12-17 19:34:28 +01:00
|
|
|
|
void ASyncDBConnection::async_query_handler(boost::system::error_code ec, std::size_t /*s*/, on_result_callback on_result)
|
2017-01-08 09:58:34 +01:00
|
|
|
|
{
|
2017-08-25 08:37:18 +02:00
|
|
|
|
if (ec == boost::system::errc::success) {
|
|
|
|
|
|
bool finished = false;
|
|
|
|
|
|
if (m_connection.consumeInput()) {
|
|
|
|
|
|
while ( ! finished && ! m_connection.isBusy()) {
|
|
|
|
|
|
auto res = m_connection.getResult();
|
|
|
|
|
|
qint64 ms = m_timer.restart();
|
2018-01-08 20:54:03 +01:00
|
|
|
|
on_result(res, ms);
|
2017-08-25 08:37:18 +02:00
|
|
|
|
if (res == nullptr) {
|
|
|
|
|
|
m_timer.invalidate();
|
|
|
|
|
|
doStateCallback(State::Connected);
|
|
|
|
|
|
finished = true;
|
|
|
|
|
|
}
|
2017-08-23 13:27:23 +02:00
|
|
|
|
}
|
2017-08-25 08:37:18 +02:00
|
|
|
|
// else is still waiting for more data
|
2017-08-23 13:27:23 +02:00
|
|
|
|
}
|
2017-08-25 08:37:18 +02:00
|
|
|
|
else {
|
|
|
|
|
|
// error during consume
|
2017-09-10 10:11:58 +02:00
|
|
|
|
auto error_msg = m_connection.getErrorMessage();
|
|
|
|
|
|
|
2017-08-25 08:37:18 +02:00
|
|
|
|
}
|
|
|
|
|
|
//return finished;
|
|
|
|
|
|
if (!finished) {
|
|
|
|
|
|
// wait for more
|
|
|
|
|
|
m_asioSock.async_read_some(null_buffers(),
|
|
|
|
|
|
[this, on_result] (boost::system::error_code ec, std::size_t s)
|
|
|
|
|
|
{ async_query_handler(ec, s, on_result); }
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
2017-08-24 21:12:32 +02:00
|
|
|
|
}
|
2017-08-23 13:27:23 +02:00
|
|
|
|
}
|
2017-01-08 09:58:34 +01:00
|
|
|
|
|
2017-08-24 21:12:32 +02:00
|
|
|
|
bool ASyncDBConnection::cancel()
|
2017-08-23 13:27:23 +02:00
|
|
|
|
{
|
2017-08-25 08:37:18 +02:00
|
|
|
|
return m_canceller.cancel(nullptr);
|
2017-08-24 21:12:32 +02:00
|
|
|
|
}
|
2017-01-08 09:58:34 +01:00
|
|
|
|
|
2017-08-24 21:12:32 +02:00
|
|
|
|
void ASyncDBConnection::processNotice(const PGresult *result)
|
2017-01-08 10:29:21 +01:00
|
|
|
|
{
|
2017-09-03 10:06:32 +02:00
|
|
|
|
Pgsql::ErrorDetails details = Pgsql::ErrorDetails::createErrorDetailsFromPGresult(result);
|
2018-01-08 20:54:03 +01:00
|
|
|
|
emit onNotice(details);
|
2017-01-08 10:29:21 +01:00
|
|
|
|
}
|