2017-08-23 08:10:01 +02:00
|
|
|
|
#include "ASyncDBConnection.h"
|
2017-01-06 07:23:40 +01:00
|
|
|
|
#include "waithandlelist.h"
|
2017-08-23 08:10:01 +02:00
|
|
|
|
#include "ScopeGuard.h"
|
2017-01-06 07:23:40 +01:00
|
|
|
|
#include <chrono>
|
2017-08-23 13:27:23 +02:00
|
|
|
|
#include <sys/select.h>
|
2017-01-03 07:22:36 +01:00
|
|
|
|
|
|
|
|
|
|
ASyncDBConnection::ASyncDBConnection()
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-01-15 21:38:07 +01:00
|
|
|
|
ASyncDBConnection::State ASyncDBConnection::state() const
|
|
|
|
|
|
{
|
|
|
|
|
|
return m_threadData.m_state;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-01-15 21:01:40 +01:00
|
|
|
|
//void ASyncDBConnection::setupConnection(const std::string &connstring)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// if (m_thread.joinable()) {
|
|
|
|
|
|
// m_threadData.stop();
|
|
|
|
|
|
// m_thread.join();
|
|
|
|
|
|
// }
|
|
|
|
|
|
// m_threadData.m_initString = connstring;
|
|
|
|
|
|
// m_thread = std::thread([this] () { m_threadData.run(); });
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
void ASyncDBConnection::setupConnection(const ConnectionConfig &config)
|
2017-01-06 07:23:40 +01:00
|
|
|
|
{
|
2017-01-09 07:38:13 +01:00
|
|
|
|
if (m_thread.joinable()) {
|
|
|
|
|
|
m_threadData.stop();
|
|
|
|
|
|
m_thread.join();
|
|
|
|
|
|
}
|
2017-01-15 21:01:40 +01:00
|
|
|
|
m_threadData.m_config = config;
|
2017-01-06 07:23:40 +01:00
|
|
|
|
m_thread = std::thread([this] () { m_threadData.run(); });
|
|
|
|
|
|
}
|
2017-01-03 07:22:36 +01:00
|
|
|
|
|
|
|
|
|
|
void ASyncDBConnection::closeConnection()
|
2017-01-06 07:23:40 +01:00
|
|
|
|
{
|
|
|
|
|
|
m_threadData.stop();
|
2017-01-08 20:00:34 +01:00
|
|
|
|
if (m_thread.joinable()) {
|
|
|
|
|
|
m_thread.join();
|
|
|
|
|
|
}
|
2017-01-06 07:23:40 +01:00
|
|
|
|
}
|
2017-01-03 07:22:36 +01:00
|
|
|
|
|
2017-01-08 09:58:34 +01:00
|
|
|
|
bool ASyncDBConnection::send(const std::string &command, on_result_callback on_result)
|
|
|
|
|
|
{
|
|
|
|
|
|
{
|
|
|
|
|
|
std::lock_guard<std::mutex> lg(m_threadData.m_commandQueue.m_mutex);
|
|
|
|
|
|
m_threadData.m_commandQueue.m_queue.emplace(command, on_result);
|
2017-08-23 13:27:23 +02:00
|
|
|
|
m_threadData.m_commandQueue.m_newEvent.notify_one();
|
2017-01-08 09:58:34 +01:00
|
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-02-19 11:12:43 +01:00
|
|
|
|
bool ASyncDBConnection::send(const std::string &command, Pgsql::Params params, on_result_callback on_result)
|
|
|
|
|
|
{
|
|
|
|
|
|
{
|
|
|
|
|
|
std::lock_guard<std::mutex> lg(m_threadData.m_commandQueue.m_mutex);
|
|
|
|
|
|
m_threadData.m_commandQueue.m_queue.emplace(command, std::move(params), on_result);
|
2017-08-23 13:27:23 +02:00
|
|
|
|
m_threadData.m_commandQueue.m_newEvent.notify_one();
|
2017-02-19 11:12:43 +01:00
|
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-01-08 09:58:34 +01:00
|
|
|
|
bool ASyncDBConnection::cancel()
|
|
|
|
|
|
{
|
|
|
|
|
|
return m_threadData.cancel();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-01-03 07:22:36 +01:00
|
|
|
|
void ASyncDBConnection::setStateCallback(on_state_callback state_callback)
|
2017-01-06 07:23:40 +01:00
|
|
|
|
{
|
2017-01-08 09:58:34 +01:00
|
|
|
|
std::lock_guard<std::mutex> lg(m_threadData.m_stateCallback.m_mutex);
|
|
|
|
|
|
m_threadData.m_stateCallback.m_func = state_callback;
|
2017-01-06 07:23:40 +01:00
|
|
|
|
}
|
2017-01-03 07:22:36 +01:00
|
|
|
|
|
2017-01-08 10:29:21 +01:00
|
|
|
|
void ASyncDBConnection::setNoticeCallback(on_notice_callback notice_callback)
|
|
|
|
|
|
{
|
|
|
|
|
|
std::lock_guard<std::mutex> lg(m_threadData.m_noticeCallback.m_mutex);
|
|
|
|
|
|
m_threadData.m_noticeCallback.m_func = notice_callback;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-01-06 07:23:40 +01:00
|
|
|
|
ASyncDBConnection::Thread::Thread()
|
|
|
|
|
|
{}
|
2017-01-03 07:22:36 +01:00
|
|
|
|
|
|
|
|
|
|
void ASyncDBConnection::Thread::run()
|
|
|
|
|
|
{
|
2017-01-08 09:58:34 +01:00
|
|
|
|
m_terminated = false;
|
2017-01-15 21:38:07 +01:00
|
|
|
|
SCOPE_EXIT {
|
|
|
|
|
|
m_state = State::NotConnected;
|
|
|
|
|
|
m_terminated = true;
|
|
|
|
|
|
};
|
2017-01-03 07:22:36 +01:00
|
|
|
|
while (!terminateRequested) {
|
|
|
|
|
|
|
|
|
|
|
|
// make or recover connection
|
|
|
|
|
|
if (makeConnection()) {
|
2017-01-08 10:29:21 +01:00
|
|
|
|
m_connection.setNoticeReceiver(
|
|
|
|
|
|
[this](const PGresult *result) { processNotice(result); });
|
2017-01-08 09:58:34 +01:00
|
|
|
|
m_canceller = m_connection.getCancel();
|
2017-01-06 07:23:40 +01:00
|
|
|
|
|
|
|
|
|
|
|
2017-01-03 07:22:36 +01:00
|
|
|
|
// send commands and receive results
|
|
|
|
|
|
communicate();
|
|
|
|
|
|
}
|
2017-01-08 09:58:34 +01:00
|
|
|
|
else {
|
|
|
|
|
|
// It is not possible to determine the source of the problem.
|
|
|
|
|
|
// Accept for PQconnectionNeedsPassword
|
2017-01-03 07:22:36 +01:00
|
|
|
|
|
2017-01-08 09:58:34 +01:00
|
|
|
|
// Pass problem to main thread and stop this thread
|
2017-01-03 07:22:36 +01:00
|
|
|
|
|
2017-01-08 09:58:34 +01:00
|
|
|
|
// Main thread needs to know it has to restart connecting if it want's to.
|
|
|
|
|
|
// TODO: add status functions to help main thread so it doesn't have to remember
|
|
|
|
|
|
// everything reported through callbacks.
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2017-01-03 07:22:36 +01:00
|
|
|
|
// close connection
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-01-08 09:58:34 +01:00
|
|
|
|
bool ASyncDBConnection::Thread::cancel()
|
|
|
|
|
|
{
|
|
|
|
|
|
return m_canceller.cancel(nullptr);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-01-03 07:22:36 +01:00
|
|
|
|
bool ASyncDBConnection::Thread::makeConnection()
|
|
|
|
|
|
{
|
2017-08-23 13:27:23 +02:00
|
|
|
|
//using namespace std::literals::chrono_literals;
|
|
|
|
|
|
|
|
|
|
|
|
// start connecting
|
|
|
|
|
|
auto keywords = m_config.getKeywords();
|
|
|
|
|
|
auto values = m_config.getValues();
|
|
|
|
|
|
#if true
|
2017-08-23 17:41:10 +02:00
|
|
|
|
bool result = m_connection.connect(keywords, values, 0);
|
|
|
|
|
|
if (result) {
|
|
|
|
|
|
doStateCallback(State::Connected);
|
|
|
|
|
|
}
|
|
|
|
|
|
return result;
|
2017-08-23 13:27:23 +02:00
|
|
|
|
#else
|
2017-01-03 07:22:36 +01:00
|
|
|
|
while (!terminateRequested) {
|
|
|
|
|
|
|
2017-01-15 21:01:40 +01:00
|
|
|
|
bool ok = m_connection.connectStart(keywords, values);
|
2017-01-06 07:23:40 +01:00
|
|
|
|
auto start = std::chrono::steady_clock::now();
|
|
|
|
|
|
if (ok && m_connection.status() != CONNECTION_BAD) {
|
|
|
|
|
|
int sock = m_connection.socket();
|
|
|
|
|
|
Win32Event socket_event(Win32Event::Reset::Auto, Win32Event::Initial::Clear);
|
2017-01-03 07:22:36 +01:00
|
|
|
|
|
2017-01-06 07:23:40 +01:00
|
|
|
|
long fd = FD_WRITE;
|
|
|
|
|
|
while (true) {
|
|
|
|
|
|
// poll till complete or failed (we can get an abort command)
|
|
|
|
|
|
WSAEventSelect(sock, socket_event.handle(), fd);
|
|
|
|
|
|
WaitHandleList whl;
|
|
|
|
|
|
auto wait_result_socket_event = whl.add(socket_event);
|
2017-08-23 13:27:23 +02:00
|
|
|
|
//auto wait_result_stop = whl.add(m_stopEvent);
|
2017-01-03 07:22:36 +01:00
|
|
|
|
|
2017-01-06 07:23:40 +01:00
|
|
|
|
auto nu = std::chrono::steady_clock::now();
|
|
|
|
|
|
std::chrono::duration<float, std::milli> diff = -(nu-start);
|
|
|
|
|
|
diff += 30s;
|
|
|
|
|
|
DWORD timeout = diff.count();
|
|
|
|
|
|
|
|
|
|
|
|
DWORD res = MsgWaitForMultipleObjectsEx(
|
|
|
|
|
|
whl.count(), // _In_ DWORD nCount,
|
|
|
|
|
|
whl, // _In_ const HANDLE *pHandles,
|
|
|
|
|
|
timeout, // _In_ DWORD dwMilliseconds,
|
|
|
|
|
|
0, // _In_ DWORD dwWakeMask,
|
|
|
|
|
|
0 // _In_ DWORD dwFlags
|
|
|
|
|
|
);
|
|
|
|
|
|
if (res == wait_result_socket_event) {
|
|
|
|
|
|
auto poll_state = m_connection.connectPoll();
|
|
|
|
|
|
if (poll_state == PGRES_POLLING_OK) {
|
|
|
|
|
|
// if connected return true
|
|
|
|
|
|
doStateCallback(State::Connected);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (poll_state == PGRES_POLLING_FAILED) {
|
|
|
|
|
|
doStateCallback(State::NotConnected);
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (poll_state == PGRES_POLLING_READING) {
|
|
|
|
|
|
doStateCallback(State::Connecting);
|
|
|
|
|
|
fd = FD_READ;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (poll_state == PGRES_POLLING_WRITING) {
|
|
|
|
|
|
doStateCallback(State::Connecting);
|
|
|
|
|
|
fd = FD_WRITE;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (res == wait_result_stop) {
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
} // end while (true)
|
|
|
|
|
|
}
|
2017-01-03 07:22:36 +01:00
|
|
|
|
}
|
|
|
|
|
|
return false;
|
2017-08-23 13:27:23 +02:00
|
|
|
|
#endif
|
2017-01-03 07:22:36 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ASyncDBConnection::Thread::communicate()
|
|
|
|
|
|
{
|
|
|
|
|
|
while (!terminateRequested) {
|
|
|
|
|
|
// wait for something to do:
|
|
|
|
|
|
// - command to send to server
|
|
|
|
|
|
// - wait for results and (notifies can also come in)
|
|
|
|
|
|
// - pass each result on to the completion routine
|
|
|
|
|
|
// - notify comming in from the server
|
|
|
|
|
|
// - pass to notify callback
|
|
|
|
|
|
// - connection raises an error
|
|
|
|
|
|
// - return
|
|
|
|
|
|
// - stop signal
|
|
|
|
|
|
// - return
|
2017-01-06 07:23:40 +01:00
|
|
|
|
|
|
|
|
|
|
|
2017-01-08 09:58:34 +01:00
|
|
|
|
if (m_state == State::Connected) {
|
|
|
|
|
|
waitForAndSendCommand();
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (m_state == State::QuerySend || m_state == State::CancelSend) {
|
|
|
|
|
|
// Wait for result, even after a cancel we should wait, for all results
|
|
|
|
|
|
// New command's are not excepted when one has been send
|
|
|
|
|
|
waitForResult();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-01-06 07:23:40 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ASyncDBConnection::Thread::stop()
|
|
|
|
|
|
{
|
|
|
|
|
|
terminateRequested = true;
|
2017-08-23 13:27:23 +02:00
|
|
|
|
//m_stopEvent.set();
|
2017-01-06 07:23:40 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ASyncDBConnection::Thread::doStateCallback(State state)
|
|
|
|
|
|
{
|
2017-01-08 09:58:34 +01:00
|
|
|
|
m_state = state;
|
|
|
|
|
|
std::lock_guard<std::mutex> lg(m_stateCallback.m_mutex);
|
|
|
|
|
|
if (m_stateCallback.m_func) {
|
|
|
|
|
|
m_stateCallback.m_func(state);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ASyncDBConnection::Thread::waitForAndSendCommand()
|
|
|
|
|
|
{
|
2017-08-23 17:41:10 +02:00
|
|
|
|
using namespace std::chrono_literals;
|
2017-08-23 13:27:23 +02:00
|
|
|
|
// lock the data
|
|
|
|
|
|
std::unique_lock<std::mutex> lk(m_commandQueue.m_mutex);
|
|
|
|
|
|
if (m_commandQueue.m_queue.empty()) {
|
|
|
|
|
|
// no data wait till there is data
|
2017-08-23 17:41:10 +02:00
|
|
|
|
m_commandQueue.m_newEvent.wait_for(lk, 1000ms);
|
2017-08-23 13:27:23 +02:00
|
|
|
|
// can we use the predicate to reimplement the stop function???, []{return ready;});
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
doNewCommand();
|
|
|
|
|
|
|
|
|
|
|
|
#if false
|
2017-01-08 09:58:34 +01:00
|
|
|
|
WaitHandleList whl;
|
|
|
|
|
|
auto wait_result_new_command = whl.add(m_commandQueue.m_newEvent);
|
2017-02-02 07:22:54 +01:00
|
|
|
|
//auto wait_result_stop =
|
2017-08-23 13:27:23 +02:00
|
|
|
|
//whl.add(m_stopEvent);
|
2017-01-08 09:58:34 +01:00
|
|
|
|
|
|
|
|
|
|
DWORD res = MsgWaitForMultipleObjectsEx(
|
|
|
|
|
|
whl.count(), // _In_ DWORD nCount,
|
|
|
|
|
|
whl, // _In_ const HANDLE *pHandles,
|
|
|
|
|
|
INFINITE, // _In_ DWORD dwMilliseconds,
|
|
|
|
|
|
0, // _In_ DWORD dwWakeMask,
|
|
|
|
|
|
0 // _In_ DWORD dwFlags
|
|
|
|
|
|
);
|
|
|
|
|
|
if (res == wait_result_new_command) {
|
|
|
|
|
|
doNewCommand();
|
|
|
|
|
|
}
|
|
|
|
|
|
// if (res == wait_result_stop) return;
|
2017-08-23 13:27:23 +02:00
|
|
|
|
#endif
|
2017-01-08 09:58:34 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ASyncDBConnection::Thread::doNewCommand()
|
|
|
|
|
|
{
|
|
|
|
|
|
// get command from top of queue (but leave it in the queue, we need the callback)
|
2017-08-23 17:41:10 +02:00
|
|
|
|
if (! m_commandQueue.m_queue.empty()) {
|
|
|
|
|
|
const Command &command = m_commandQueue.m_queue.front();
|
|
|
|
|
|
if (!command.command.empty()) {
|
|
|
|
|
|
bool query_send = false;
|
|
|
|
|
|
if (command.params.empty())
|
|
|
|
|
|
query_send = m_connection.sendQuery(command.command.c_str());
|
|
|
|
|
|
else
|
|
|
|
|
|
query_send = m_connection.sendQueryParams(command.command.c_str(), command.params);
|
|
|
|
|
|
|
|
|
|
|
|
if (query_send) {
|
|
|
|
|
|
m_timer.start();
|
|
|
|
|
|
doStateCallback(State::QuerySend);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
std::string error = m_connection.getErrorMessage();
|
|
|
|
|
|
// todo: need to report the error
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2017-02-19 11:12:43 +01:00
|
|
|
|
|
2017-01-08 09:58:34 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-08-23 13:27:23 +02:00
|
|
|
|
bool ASyncDBConnection::Thread::consumeResultInput()
|
2017-01-08 09:58:34 +01:00
|
|
|
|
{
|
2017-08-23 13:27:23 +02:00
|
|
|
|
bool finished = false;
|
|
|
|
|
|
if (m_connection.consumeInput()) {
|
|
|
|
|
|
while ( ! finished && ! m_connection.isBusy()) {
|
|
|
|
|
|
auto res(m_connection.getResult());
|
|
|
|
|
|
{
|
|
|
|
|
|
qint64 ms = m_timer.restart();
|
|
|
|
|
|
std::lock_guard<std::mutex> lg(m_commandQueue.m_mutex);
|
|
|
|
|
|
m_commandQueue.m_queue.front().on_result(res, ms);
|
|
|
|
|
|
if (res == nullptr) {
|
|
|
|
|
|
m_timer.invalidate();
|
|
|
|
|
|
m_commandQueue.m_queue.pop();
|
|
|
|
|
|
doStateCallback(State::Connected);
|
|
|
|
|
|
finished = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
// else is still waiting for more data
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
// error during consume
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
return finished;
|
|
|
|
|
|
}
|
2017-01-08 09:58:34 +01:00
|
|
|
|
|
2017-08-23 13:27:23 +02:00
|
|
|
|
void ASyncDBConnection::Thread::waitForResult()
|
|
|
|
|
|
{
|
2017-01-08 09:58:34 +01:00
|
|
|
|
int sock = m_connection.socket();
|
2017-08-23 13:27:23 +02:00
|
|
|
|
|
|
|
|
|
|
fd_set readfds;
|
|
|
|
|
|
timeval timeout;
|
|
|
|
|
|
bool finished = false;
|
|
|
|
|
|
while (!finished && !terminateRequested) {
|
|
|
|
|
|
FD_ZERO(&readfds);
|
|
|
|
|
|
FD_SET(sock, &readfds);
|
|
|
|
|
|
|
|
|
|
|
|
timeout.tv_sec = 5;
|
|
|
|
|
|
timeout.tv_usec = 0;
|
|
|
|
|
|
|
2017-08-23 17:41:10 +02:00
|
|
|
|
int select_result = select(sock + 1, &readfds, nullptr, nullptr, &timeout);
|
2017-08-23 13:27:23 +02:00
|
|
|
|
if (select_result > 0) {
|
|
|
|
|
|
if (FD_ISSET(sock, &readfds)) {
|
|
|
|
|
|
if (consumeResultInput()) {
|
|
|
|
|
|
finished = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
#if false
|
2017-01-08 15:15:40 +01:00
|
|
|
|
Win32Event socket_event(Win32Event::Reset::Manual, Win32Event::Initial::Clear);
|
2017-01-08 09:58:34 +01:00
|
|
|
|
|
2017-01-08 15:15:40 +01:00
|
|
|
|
long fd = FD_READ | FD_CLOSE;
|
2017-01-08 09:58:34 +01:00
|
|
|
|
|
2017-01-08 15:15:40 +01:00
|
|
|
|
bool finished = false;
|
|
|
|
|
|
while ( ! finished) {
|
2017-01-08 09:58:34 +01:00
|
|
|
|
WSAEventSelect(sock, socket_event.handle(), fd);
|
|
|
|
|
|
|
|
|
|
|
|
WaitHandleList whl;
|
|
|
|
|
|
auto wait_result_socket = whl.add(socket_event);
|
2017-08-23 13:27:23 +02:00
|
|
|
|
//auto wait_result_stop = whl.add(m_stopEvent);
|
2017-01-08 09:58:34 +01:00
|
|
|
|
|
|
|
|
|
|
DWORD res = MsgWaitForMultipleObjectsEx(
|
|
|
|
|
|
whl.count(), // _In_ DWORD nCount,
|
|
|
|
|
|
whl, // _In_ const HANDLE *pHandles,
|
|
|
|
|
|
INFINITE, // _In_ DWORD dwMilliseconds,
|
|
|
|
|
|
0, // _In_ DWORD dwWakeMask,
|
|
|
|
|
|
0 // _In_ DWORD dwFlags
|
|
|
|
|
|
);
|
|
|
|
|
|
if (res == wait_result_socket) {
|
2017-01-08 15:15:40 +01:00
|
|
|
|
WSANETWORKEVENTS net_events;
|
|
|
|
|
|
WSAEnumNetworkEvents(sock, socket_event.handle(), &net_events);
|
|
|
|
|
|
|
|
|
|
|
|
if (net_events.lNetworkEvents & FD_READ) {
|
2017-08-23 13:27:23 +02:00
|
|
|
|
if (consumeResultInput()) {
|
|
|
|
|
|
finished = true;
|
|
|
|
|
|
}
|
2017-01-08 09:58:34 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (res == wait_result_stop) {
|
|
|
|
|
|
// Send cancel, close connection and terminate thread
|
|
|
|
|
|
cancel();
|
|
|
|
|
|
doStateCallback(State::Terminating);
|
2017-01-08 15:15:40 +01:00
|
|
|
|
finished = true;
|
2017-01-08 09:58:34 +01:00
|
|
|
|
}
|
|
|
|
|
|
} // end while
|
|
|
|
|
|
// When last result received, remove command from queue
|
2017-08-23 13:27:23 +02:00
|
|
|
|
#endif
|
2017-01-03 07:22:36 +01:00
|
|
|
|
}
|
2017-01-08 09:58:34 +01:00
|
|
|
|
|
2017-01-08 10:29:21 +01:00
|
|
|
|
void ASyncDBConnection::Thread::processNotice(const PGresult *result)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Pgsql::Result res(result);
|
|
|
|
|
|
std::lock_guard<std::mutex> lg(m_noticeCallback.m_mutex);
|
|
|
|
|
|
if (m_noticeCallback.m_func) {
|
|
|
|
|
|
Pgsql::ErrorDetails details = Pgsql::ErrorDetails::createErrorDetailsFromPGresult(result);
|
|
|
|
|
|
m_noticeCallback.m_func(details);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|