Merge branch 'port-to-linux'
This commit is contained in:
commit
976623ca9b
180 changed files with 1150 additions and 1415 deletions
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
*.swp
|
||||||
|
build/*
|
||||||
|
*.kdev4
|
||||||
|
.kdev4/*
|
||||||
|
|
||||||
18
BUILD
Normal file
18
BUILD
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
|
||||||
|
If it doesn't detect Qt CMAKE_PREFIX_PATH needs to be set
|
||||||
|
|
||||||
|
export CMAKE_PREFIX_PATH=/usr/lib/x86_64-linux-gnu/qt5/mkspecs/features/data/cmake
|
||||||
|
|
||||||
|
Dependencies:
|
||||||
|
- boost (asio, system, ???)
|
||||||
|
- Botan-2
|
||||||
|
- libpq
|
||||||
|
- Qt5
|
||||||
|
- fmt (should we include this one in the project?
|
||||||
|
|
||||||
|
|
||||||
|
- jsoncpp (included)
|
||||||
|
|
||||||
|
On ubuntu
|
||||||
|
|
||||||
|
sudo apt install libpq-dev libboost1.63-all-dev
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
#include "Core.h"
|
|
||||||
|
|
||||||
|
|
||||||
Core::Core()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
12
core/Core.h
12
core/Core.h
|
|
@ -1,12 +0,0 @@
|
||||||
#ifndef CORE_H
|
|
||||||
#define CORE_H
|
|
||||||
|
|
||||||
|
|
||||||
class Core
|
|
||||||
{
|
|
||||||
|
|
||||||
public:
|
|
||||||
Core();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // CORE_H
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
#-------------------------------------------------
|
|
||||||
#
|
|
||||||
# Project created by QtCreator 2017-02-26T10:51:14
|
|
||||||
#
|
|
||||||
#-------------------------------------------------
|
|
||||||
|
|
||||||
QT -= gui
|
|
||||||
|
|
||||||
TARGET = core
|
|
||||||
TEMPLATE = lib
|
|
||||||
CONFIG += staticlib c++14
|
|
||||||
|
|
||||||
INCLUDEPATH += C:\prog\include C:\VSproj\boost_1_63_0
|
|
||||||
DEFINES += WIN32_LEAN_AND_MEAN NOMINMAX
|
|
||||||
#LIBS += /LIBPATH:C:\VSproj\boost_1_63_0\stage\lib /LIBPATH:c:\prog\lib\ libpq.lib fmt.lib User32.lib ws2_32.lib
|
|
||||||
|
|
||||||
|
|
||||||
# The following define makes your compiler emit warnings if you use
|
|
||||||
# any feature of Qt which as been marked as deprecated (the exact warnings
|
|
||||||
# depend on your compiler). Please consult the documentation of the
|
|
||||||
# deprecated API in order to know how to port your code away from it.
|
|
||||||
DEFINES += QT_DEPRECATED_WARNINGS
|
|
||||||
|
|
||||||
# You can also make your code fail to compile if you use deprecated APIs.
|
|
||||||
# In order to do so, uncomment the following line.
|
|
||||||
# You can also select to disable deprecated APIs only up to a certain version of Qt.
|
|
||||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
|
||||||
|
|
||||||
SOURCES += Core.cpp \
|
|
||||||
my_boost_assert_handler.cpp \
|
|
||||||
SqlLexer.cpp \
|
|
||||||
PasswordManager.cpp \
|
|
||||||
CsvWriter.cpp \
|
|
||||||
BackupFormatModel.cpp
|
|
||||||
|
|
||||||
HEADERS += Core.h \
|
|
||||||
PasswordManager.h \
|
|
||||||
SqlLexer.h \
|
|
||||||
ScopeGuard.h \
|
|
||||||
CsvWriter.h \
|
|
||||||
BackupFormatModel.h
|
|
||||||
unix {
|
|
||||||
target.path = /usr/lib
|
|
||||||
INSTALLS += target
|
|
||||||
}
|
|
||||||
10
pglabAll.pro
10
pglabAll.pro
|
|
@ -1,10 +0,0 @@
|
||||||
TEMPLATE = subdirs
|
|
||||||
|
|
||||||
DEFINES += BOOST_ENABLE_ASSERT_HANDLER
|
|
||||||
|
|
||||||
SUBDIRS += src \
|
|
||||||
core
|
|
||||||
|
|
||||||
CONFIG(debug, debug|release) {
|
|
||||||
SUBDIRS += tests
|
|
||||||
}
|
|
||||||
|
|
@ -1,352 +0,0 @@
|
||||||
#include "asyncdbconnection.h"
|
|
||||||
#include "waithandlelist.h"
|
|
||||||
#include "scopeguard.h"
|
|
||||||
#include <chrono>
|
|
||||||
|
|
||||||
ASyncDBConnection::ASyncDBConnection()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ASyncDBConnection::State ASyncDBConnection::state() const
|
|
||||||
{
|
|
||||||
return m_threadData.m_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
//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)
|
|
||||||
{
|
|
||||||
if (m_thread.joinable()) {
|
|
||||||
m_threadData.stop();
|
|
||||||
m_thread.join();
|
|
||||||
}
|
|
||||||
m_threadData.m_config = config;
|
|
||||||
m_thread = std::thread([this] () { m_threadData.run(); });
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASyncDBConnection::closeConnection()
|
|
||||||
{
|
|
||||||
m_threadData.stop();
|
|
||||||
if (m_thread.joinable()) {
|
|
||||||
m_thread.join();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
m_threadData.m_commandQueue.m_newEvent.set();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
m_threadData.m_commandQueue.m_newEvent.set();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ASyncDBConnection::cancel()
|
|
||||||
{
|
|
||||||
return m_threadData.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASyncDBConnection::setStateCallback(on_state_callback state_callback)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lg(m_threadData.m_stateCallback.m_mutex);
|
|
||||||
m_threadData.m_stateCallback.m_func = state_callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASyncDBConnection::Thread::Thread()
|
|
||||||
: m_stopEvent(Win32Event::Reset::Manual, Win32Event::Initial::Clear)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void ASyncDBConnection::Thread::run()
|
|
||||||
{
|
|
||||||
m_terminated = false;
|
|
||||||
SCOPE_EXIT {
|
|
||||||
m_state = State::NotConnected;
|
|
||||||
m_terminated = true;
|
|
||||||
};
|
|
||||||
while (!terminateRequested) {
|
|
||||||
|
|
||||||
// make or recover connection
|
|
||||||
if (makeConnection()) {
|
|
||||||
m_connection.setNoticeReceiver(
|
|
||||||
[this](const PGresult *result) { processNotice(result); });
|
|
||||||
m_canceller = m_connection.getCancel();
|
|
||||||
|
|
||||||
|
|
||||||
// send commands and receive results
|
|
||||||
communicate();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// It is not possible to determine the source of the problem.
|
|
||||||
// Accept for PQconnectionNeedsPassword
|
|
||||||
|
|
||||||
// Pass problem to main thread and stop this thread
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// close connection
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ASyncDBConnection::Thread::cancel()
|
|
||||||
{
|
|
||||||
return m_canceller.cancel(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ASyncDBConnection::Thread::makeConnection()
|
|
||||||
{
|
|
||||||
using namespace std::chrono_literals;
|
|
||||||
|
|
||||||
while (!terminateRequested) {
|
|
||||||
|
|
||||||
// start connecting
|
|
||||||
//bool ok = m_connection.connectStart(m_initString + " client_encoding=utf8");
|
|
||||||
auto keywords = m_config.getKeywords();
|
|
||||||
auto values = m_config.getValues();
|
|
||||||
bool ok = m_connection.connectStart(keywords, values);
|
|
||||||
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);
|
|
||||||
|
|
||||||
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);
|
|
||||||
auto wait_result_stop = whl.add(m_stopEvent);
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASyncDBConnection::Thread::stop()
|
|
||||||
{
|
|
||||||
terminateRequested = true;
|
|
||||||
m_stopEvent.set();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASyncDBConnection::Thread::doStateCallback(State state)
|
|
||||||
{
|
|
||||||
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()
|
|
||||||
{
|
|
||||||
WaitHandleList whl;
|
|
||||||
auto wait_result_new_command = whl.add(m_commandQueue.m_newEvent);
|
|
||||||
//auto wait_result_stop =
|
|
||||||
whl.add(m_stopEvent);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASyncDBConnection::Thread::doNewCommand()
|
|
||||||
{
|
|
||||||
// todo: send command
|
|
||||||
// get command from top of queue (but leave it in the queue, we need the callback)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lg(m_commandQueue.m_mutex);
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASyncDBConnection::Thread::waitForResult()
|
|
||||||
{
|
|
||||||
|
|
||||||
int sock = m_connection.socket();
|
|
||||||
Win32Event socket_event(Win32Event::Reset::Manual, Win32Event::Initial::Clear);
|
|
||||||
|
|
||||||
long fd = FD_READ | FD_CLOSE;
|
|
||||||
|
|
||||||
bool finished = false;
|
|
||||||
while ( ! finished) {
|
|
||||||
WSAEventSelect(sock, socket_event.handle(), fd);
|
|
||||||
|
|
||||||
WaitHandleList whl;
|
|
||||||
auto wait_result_socket = whl.add(socket_event);
|
|
||||||
auto wait_result_stop = whl.add(m_stopEvent);
|
|
||||||
|
|
||||||
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) {
|
|
||||||
WSANETWORKEVENTS net_events;
|
|
||||||
WSAEnumNetworkEvents(sock, socket_event.handle(), &net_events);
|
|
||||||
|
|
||||||
if (net_events.lNetworkEvents & FD_READ) {
|
|
||||||
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
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (res == wait_result_stop) {
|
|
||||||
// Send cancel, close connection and terminate thread
|
|
||||||
cancel();
|
|
||||||
doStateCallback(State::Terminating);
|
|
||||||
finished = true;
|
|
||||||
}
|
|
||||||
} // end while
|
|
||||||
// When last result received, remove command from queue
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,137 +0,0 @@
|
||||||
#ifndef ASYNCDBCONNECTION_H
|
|
||||||
#define ASYNCDBCONNECTION_H
|
|
||||||
|
|
||||||
#include "PgsqlConn.h"
|
|
||||||
#include "Pgsql_Params.h"
|
|
||||||
#include "win32event.h"
|
|
||||||
#include "connectionconfig.h"
|
|
||||||
#include <QElapsedTimer>
|
|
||||||
#include <functional>
|
|
||||||
#include <mutex>
|
|
||||||
#include <queue>
|
|
||||||
#include <vector>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
/** \brief Class that handles asynchronous execution of queries.
|
|
||||||
*
|
|
||||||
* Queries are passed to this class with a routine to call on completion
|
|
||||||
* when the result is on that routine is called.
|
|
||||||
*/
|
|
||||||
class ASyncDBConnection {
|
|
||||||
public:
|
|
||||||
enum class State {
|
|
||||||
NotConnected,
|
|
||||||
Connecting,
|
|
||||||
Connected,
|
|
||||||
QuerySend,
|
|
||||||
CancelSend,
|
|
||||||
Terminating
|
|
||||||
};
|
|
||||||
|
|
||||||
using on_result_callback = std::function<void(std::shared_ptr<Pgsql::Result>, qint64)>;
|
|
||||||
using on_state_callback = std::function<void(State)>;
|
|
||||||
using on_notice_callback = std::function<void(Pgsql::ErrorDetails)>;
|
|
||||||
|
|
||||||
ASyncDBConnection();
|
|
||||||
|
|
||||||
State state() const;
|
|
||||||
// void setupConnection(const std::string &connstring);
|
|
||||||
void setupConnection(const ConnectionConfig &config);
|
|
||||||
void closeConnection();
|
|
||||||
|
|
||||||
void setStateCallback(on_state_callback state_callback);
|
|
||||||
void setNoticeCallback(on_notice_callback notice_callback);
|
|
||||||
|
|
||||||
/** Sends command to the server.
|
|
||||||
|
|
||||||
When the result is in on_result will be called directly within the thread.
|
|
||||||
|
|
||||||
If the command gives multiple results on_result will be called for each result.
|
|
||||||
*/
|
|
||||||
bool send(const std::string &command, on_result_callback on_result);
|
|
||||||
bool send(const std::string &command, Pgsql::Params params, on_result_callback on_result);
|
|
||||||
|
|
||||||
bool cancel();
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
class Command {
|
|
||||||
public:
|
|
||||||
std::string command;
|
|
||||||
Pgsql::Params params;
|
|
||||||
on_result_callback on_result;
|
|
||||||
|
|
||||||
Command() = default;
|
|
||||||
Command(const std::string &cmd, on_result_callback cb)
|
|
||||||
: command(cmd), on_result(cb)
|
|
||||||
{}
|
|
||||||
Command(const std::string &cmd, Pgsql::Params &&p, on_result_callback cb)
|
|
||||||
: command(cmd), params(p), on_result(cb)
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Contains all the members accessed by the thread
|
|
||||||
class Thread {
|
|
||||||
public:
|
|
||||||
using t_CommandQueue = std::queue<Command>;
|
|
||||||
struct {
|
|
||||||
std::mutex m_mutex;
|
|
||||||
on_state_callback m_func;
|
|
||||||
} m_stateCallback;
|
|
||||||
struct {
|
|
||||||
std::mutex m_mutex;
|
|
||||||
on_notice_callback m_func;
|
|
||||||
} m_noticeCallback;
|
|
||||||
|
|
||||||
struct t_Command {
|
|
||||||
std::mutex m_mutex;
|
|
||||||
t_CommandQueue m_queue;
|
|
||||||
Win32Event m_newEvent;
|
|
||||||
t_Command()
|
|
||||||
: m_newEvent(Win32Event::Reset::Auto, Win32Event::Initial::Clear)
|
|
||||||
{}
|
|
||||||
} m_commandQueue;
|
|
||||||
|
|
||||||
// std::string m_initString;
|
|
||||||
ConnectionConfig m_config;
|
|
||||||
State m_state = State::NotConnected;
|
|
||||||
|
|
||||||
Thread();
|
|
||||||
|
|
||||||
/// Is started as a seperate thread by ASyncDBConnection
|
|
||||||
void run();
|
|
||||||
|
|
||||||
/// Sends a cancel request to the DB server
|
|
||||||
bool cancel();
|
|
||||||
|
|
||||||
void stop();
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
|
|
||||||
Win32Event m_stopEvent;
|
|
||||||
Pgsql::Connection m_connection;
|
|
||||||
bool terminateRequested = false; ///< is set when the thread should stop
|
|
||||||
bool m_terminated = true;
|
|
||||||
Pgsql::Canceller m_canceller;
|
|
||||||
QElapsedTimer m_timer;
|
|
||||||
|
|
||||||
|
|
||||||
bool makeConnection();
|
|
||||||
void communicate();
|
|
||||||
|
|
||||||
void doStateCallback(State state);
|
|
||||||
/// Wait's for a command to come in and send's it to the server
|
|
||||||
void waitForAndSendCommand();
|
|
||||||
void doNewCommand();
|
|
||||||
void waitForResult();
|
|
||||||
|
|
||||||
|
|
||||||
void processNotice(const PGresult *result);
|
|
||||||
};
|
|
||||||
|
|
||||||
Thread m_threadData;
|
|
||||||
std::thread m_thread;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // ASYNCDBCONNECTION_H
|
|
||||||
78
src/CMakeLists.txt
Normal file
78
src/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
cmake_minimum_required(VERSION 3.2 FATAL_ERROR)
|
||||||
|
project(pglaball VERSION 0.1 LANGUAGES CXX)
|
||||||
|
|
||||||
|
set (CMAKE_PREFIX_PATH /usr/lib/x86_64-linux-gnu/qt5/mkspecs/features/data/cmake)
|
||||||
|
set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
|
||||||
|
|
||||||
|
# Must use GNUInstallDirs to install libraries into correct
|
||||||
|
# locations on all platforms.
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
|
include(CheckCXXCompilerFlag)
|
||||||
|
|
||||||
|
function(enable_cxx_compiler_flag_if_supported flag)
|
||||||
|
string(FIND "${CMAKE_CXX_FLAGS}" "${flag}" flag_already_set)
|
||||||
|
if(flag_already_set EQUAL -1)
|
||||||
|
check_cxx_compiler_flag("${flag}" flag_supported)
|
||||||
|
if(flag_supported)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flag}" PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
unset(flag_supported CACHE)
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
|
||||||
|
enable_cxx_compiler_flag_if_supported("-Wall")
|
||||||
|
|
||||||
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||||
|
# set(CMAKE_CXX_STANDARD 14)
|
||||||
|
# set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
# Find includes in corresponding build directories
|
||||||
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
|
# Instruct CMake to run moc automatically when needed.
|
||||||
|
|
||||||
|
find_package(Botan REQUIRED)
|
||||||
|
add_library(botan UNKNOWN IMPORTED)
|
||||||
|
set_property(TARGET botan PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${BOTAN_INCLUDE_DIRS})
|
||||||
|
set_property(TARGET botan PROPERTY IMPORTED_LOCATION ${BOTAN_LIBRARIES})
|
||||||
|
|
||||||
|
find_package(PostgreSQL REQUIRED)
|
||||||
|
add_library(postgresql UNKNOWN IMPORTED)
|
||||||
|
set_property(TARGET postgresql PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${PostgreSQL_INCLUDE_DIRS})
|
||||||
|
set_property(TARGET postgresql PROPERTY IMPORTED_LOCATION ${PostgreSQL_LIBRARIES})
|
||||||
|
|
||||||
|
find_package(Qt5Widgets 5.7 REQUIRED)
|
||||||
|
add_library(Qt5Widgets INTERFACE IMPORTED)
|
||||||
|
set_property(TARGET Qt5Widgets PROPERTY
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES ${Qt5Widgets_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
find_package(Fmt 4.0 REQUIRED)
|
||||||
|
add_library(fmt INTERFACE IMPORTED)
|
||||||
|
set_property(TARGET fmt PROPERTY
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES ${fmt_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
find_package(Boost 1.63 COMPONENTS system REQUIRED )
|
||||||
|
add_library(boost INTERFACE IMPORTED)
|
||||||
|
set_property(TARGET boost PROPERTY
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES ${Boost_INCLUDE_DIR})
|
||||||
|
|
||||||
|
add_library(boost-system SHARED IMPORTED)
|
||||||
|
set_property(TARGET boost-system PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${Boost_INCLUDE_DIRS})
|
||||||
|
set_property(TARGET boost-system PROPERTY IMPORTED_LOCATION ${Boost_SYSTEM_LIBRARY})
|
||||||
|
|
||||||
|
find_package(GTest REQUIRED)
|
||||||
|
add_library(gtest UNKNOWN IMPORTED)
|
||||||
|
set_property(TARGET gtest PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${GTEST_INCLUDE_DIRS})
|
||||||
|
set_property(TARGET gtest PROPERTY IMPORTED_LOCATION ${GTEST_LIBRARIES})
|
||||||
|
|
||||||
|
find_package(Threads)
|
||||||
|
|
||||||
|
enable_testing()
|
||||||
|
|
||||||
|
add_subdirectory(core)
|
||||||
|
add_subdirectory(pgsql)
|
||||||
|
add_subdirectory(pglab)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
#include "pgtype.h"
|
|
||||||
#include "PgsqlConn.h"
|
|
||||||
|
|
||||||
PgType::PgType() = default;
|
|
||||||
|
|
||||||
49
src/cmake/Modules/FindBotan.cmake
Normal file
49
src/cmake/Modules/FindBotan.cmake
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
# - Try to find the Botan library
|
||||||
|
#
|
||||||
|
# Once done this will define
|
||||||
|
#
|
||||||
|
# BOTAN_FOUND - System has Botan
|
||||||
|
# BOTAN_INCLUDE_DIR - The Botan include directory
|
||||||
|
# BOTAN_LIBRARIES - The libraries needed to use Botan
|
||||||
|
# BOTAN_DEFINITIONS - Compiler switches required for using Botan
|
||||||
|
|
||||||
|
IF (BOTAN_INCLUDE_DIR AND BOTAN_LIBRARY)
|
||||||
|
# in cache already
|
||||||
|
SET(Botan_FIND_QUIETLY TRUE)
|
||||||
|
ENDIF (BOTAN_INCLUDE_DIR AND BOTAN_LIBRARY)
|
||||||
|
|
||||||
|
IF (NOT WIN32)
|
||||||
|
# try using pkg-config to get the directories and then use these values
|
||||||
|
# in the FIND_PATH() and FIND_LIBRARY() calls
|
||||||
|
# also fills in BOTAN_DEFINITIONS, although that isn't normally useful
|
||||||
|
FIND_PACKAGE(PkgConfig)
|
||||||
|
PKG_SEARCH_MODULE(PC_BOTAN botan-2)
|
||||||
|
SET(BOTAN_DEFINITIONS ${PC_BOTAN_CFLAGS})
|
||||||
|
ENDIF (NOT WIN32)
|
||||||
|
|
||||||
|
FIND_PATH(BOTAN_INCLUDE_DIR botan/botan.h
|
||||||
|
HINTS
|
||||||
|
${PC_BOTAN_INCLUDEDIR}
|
||||||
|
${PC_BOTAN_INCLUDE_DIRS}
|
||||||
|
/usr/local/include/botan-2
|
||||||
|
)
|
||||||
|
|
||||||
|
FIND_LIBRARY(BOTAN_LIBRARY botan-2
|
||||||
|
NAMES ${PC_BOTAN_LIBRARIES}
|
||||||
|
HINTS
|
||||||
|
${PC_BOTAN_LIBDIR}
|
||||||
|
${PC_BOTAN_LIBRARY_DIRS}
|
||||||
|
/usr/local/lib
|
||||||
|
)
|
||||||
|
|
||||||
|
MARK_AS_ADVANCED(BOTAN_INCLUDE_DIR BOTAN_LIBRARY)
|
||||||
|
|
||||||
|
# handle the QUIETLY and REQUIRED arguments and set BOTAN_FOUND to TRUE if
|
||||||
|
# all listed variables are TRUE
|
||||||
|
INCLUDE(FindPackageHandleStandardArgs)
|
||||||
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Botan DEFAULT_MSG BOTAN_LIBRARY BOTAN_INCLUDE_DIR)
|
||||||
|
|
||||||
|
IF(BOTAN_FOUND)
|
||||||
|
SET(BOTAN_LIBRARIES ${BOTAN_LIBRARY})
|
||||||
|
SET(BOTAN_INCLUDE_DIRS ${BOTAN_INCLUDE_DIR})
|
||||||
|
ENDIF()
|
||||||
41
src/core/CMakeLists.txt
Normal file
41
src/core/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
|
||||||
|
add_library(core STATIC
|
||||||
|
BackupFormatModel.cpp
|
||||||
|
CsvWriter.cpp
|
||||||
|
my_boost_assert_handler.cpp
|
||||||
|
PasswordManager.cpp
|
||||||
|
SqlLexer.cpp)
|
||||||
|
|
||||||
|
target_link_libraries(core PUBLIC
|
||||||
|
boost
|
||||||
|
botan
|
||||||
|
Qt5::Core
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(core INTERFACE
|
||||||
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||||
|
)
|
||||||
|
|
||||||
|
set_target_properties(core PROPERTIES
|
||||||
|
CXX_STANDARD 14
|
||||||
|
CXX_STANDARD_REQUIRED ON
|
||||||
|
POSITION_INDEPENDENT_CODE True
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(runtests
|
||||||
|
test/main.cpp
|
||||||
|
test/tst_CsvWriter.cpp
|
||||||
|
test/tst_expected.cpp
|
||||||
|
test/tst_PasswordManager.cpp
|
||||||
|
test/tst_scopeguard.cpp
|
||||||
|
test/tst_SqlLexer.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(runtests
|
||||||
|
core
|
||||||
|
gtest
|
||||||
|
Threads::Threads
|
||||||
|
)
|
||||||
|
|
||||||
|
add_test(tests runtests)
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#include "csvwriter.h"
|
#include "CsvWriter.h"
|
||||||
|
|
||||||
CsvWriter::CsvWriter()
|
CsvWriter::CsvWriter()
|
||||||
{}
|
{}
|
||||||
|
|
@ -27,7 +27,7 @@ public:
|
||||||
|
|
||||||
|
|
||||||
Expected(const Expected& rhs)
|
Expected(const Expected& rhs)
|
||||||
: m_valid(rhs.valid)
|
: m_valid(rhs.m_valid)
|
||||||
{
|
{
|
||||||
if (m_valid) {
|
if (m_valid) {
|
||||||
new (&m_value) T(rhs.m_value);
|
new (&m_value) T(rhs.m_value);
|
||||||
|
|
@ -13,7 +13,6 @@
|
||||||
|
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
|
|
||||||
#include "Core.h"
|
|
||||||
|
|
||||||
using namespace Botan;
|
using namespace Botan;
|
||||||
|
|
||||||
|
|
@ -29,7 +29,8 @@ QChar SqlLexer::peekChar()
|
||||||
* @param ofs
|
* @param ofs
|
||||||
* @param start
|
* @param start
|
||||||
* @param length
|
* @param length
|
||||||
* @return false when input seems invalid, it will return what it did recognize but something wasn't right, parser should try to recover
|
* @return false when input seems invalid, it will return what it did recognize but something
|
||||||
|
* wasn't right, parser should try to recover
|
||||||
*/
|
*/
|
||||||
bool SqlLexer::nextBasicToken(int &startpos, int &length, BasicTokenType &tokentype, QString &out)
|
bool SqlLexer::nextBasicToken(int &startpos, int &length, BasicTokenType &tokentype, QString &out)
|
||||||
{
|
{
|
||||||
|
|
@ -117,6 +118,46 @@ bool SqlLexer::nextBasicToken(int &startpos, int &length, BasicTokenType &tokent
|
||||||
else if (c == QChar::Null) {
|
else if (c == QChar::Null) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
else if (c == '$') {
|
||||||
|
c = nextChar();
|
||||||
|
if (c.isDigit()) {
|
||||||
|
for (;;) {
|
||||||
|
c = peekChar();
|
||||||
|
if (c.isDigit())
|
||||||
|
nextChar();
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tokentype = BasicTokenType::Parameter;
|
||||||
|
length = m_pos - startpos;
|
||||||
|
QStringRef sr(&m_block, startpos, length);
|
||||||
|
out = sr.toString();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (c.isLetter()) {
|
||||||
|
// is this a dollar quote?
|
||||||
|
while (true) {
|
||||||
|
c = nextChar();
|
||||||
|
if (c == '$') {
|
||||||
|
// Found valid dollar quote
|
||||||
|
tokentype = BasicTokenType::DollarQuote;
|
||||||
|
length = m_pos - startpos;
|
||||||
|
QStringRef sr(&m_block, startpos, length);
|
||||||
|
out = sr.toString();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (!c.isLetter()) {
|
||||||
|
// ERROR, unallowed character
|
||||||
|
tokentype = BasicTokenType::None;
|
||||||
|
length = m_pos - startpos;
|
||||||
|
QStringRef sr(&m_block, startpos, length);
|
||||||
|
out = sr.toString();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
// Undetermined symbol
|
// Undetermined symbol
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
|
@ -11,8 +11,9 @@ enum class BasicTokenType {
|
||||||
BlockComment,
|
BlockComment,
|
||||||
OpenBlockComment, // Busy with a block comment end not detected before end of current input
|
OpenBlockComment, // Busy with a block comment end not detected before end of current input
|
||||||
QuotedString,
|
QuotedString,
|
||||||
DollarQuotedString,
|
DollarQuote, // Return the dollar quote tag, do not consume the entire string (potentially long)
|
||||||
QuotedIdentifier
|
QuotedIdentifier,
|
||||||
|
Parameter
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class LexerState {
|
enum class LexerState {
|
||||||
8
src/core/test/main.cpp
Normal file
8
src/core/test/main.cpp
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
||||||
|
|
@ -19,7 +19,7 @@ TEST(CsvWriter, one_row_two_numbers)
|
||||||
writer.nextRow();
|
writer.nextRow();
|
||||||
|
|
||||||
QString expected = QString::fromUtf8("1,2\n");
|
QString expected = QString::fromUtf8("1,2\n");
|
||||||
ASSERT_THAT(result, Eq(expected));
|
ASSERT_EQ(result, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(CsvWriter, one_row_one_number_one_unquoted_string)
|
TEST(CsvWriter, one_row_one_number_one_unquoted_string)
|
||||||
|
|
@ -34,7 +34,7 @@ TEST(CsvWriter, one_row_one_number_one_unquoted_string)
|
||||||
writer.nextRow();
|
writer.nextRow();
|
||||||
|
|
||||||
QString expected = QString::fromUtf8("1,hello\n");
|
QString expected = QString::fromUtf8("1,hello\n");
|
||||||
ASSERT_THAT(result, Eq(expected));
|
ASSERT_EQ(result, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(CsvWriter, one_row_one_number_one_quoted_string)
|
TEST(CsvWriter, one_row_one_number_one_quoted_string)
|
||||||
|
|
@ -49,7 +49,7 @@ TEST(CsvWriter, one_row_one_number_one_quoted_string)
|
||||||
writer.nextRow();
|
writer.nextRow();
|
||||||
|
|
||||||
QString expected = QString::fromUtf8("1,\"hel,lo\"\n");
|
QString expected = QString::fromUtf8("1,\"hel,lo\"\n");
|
||||||
ASSERT_THAT(result, Eq(expected));
|
ASSERT_EQ(result, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(CsvWriter, newline_in_field)
|
TEST(CsvWriter, newline_in_field)
|
||||||
|
|
@ -64,7 +64,7 @@ TEST(CsvWriter, newline_in_field)
|
||||||
writer.nextRow();
|
writer.nextRow();
|
||||||
|
|
||||||
QString expected = QString::fromUtf8("1,\"hel\nlo\"\n");
|
QString expected = QString::fromUtf8("1,\"hel\nlo\"\n");
|
||||||
ASSERT_THAT(result, Eq(expected));
|
ASSERT_EQ(result, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(CsvWriter, escape_quote)
|
TEST(CsvWriter, escape_quote)
|
||||||
|
|
@ -79,7 +79,7 @@ TEST(CsvWriter, escape_quote)
|
||||||
writer.nextRow();
|
writer.nextRow();
|
||||||
|
|
||||||
QString expected = QString::fromUtf8("1,\"hel\"\"lo\"\n");
|
QString expected = QString::fromUtf8("1,\"hel\"\"lo\"\n");
|
||||||
ASSERT_THAT(result, Eq(expected));
|
ASSERT_EQ(result, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(CsvWriter, non_default_seperator)
|
TEST(CsvWriter, non_default_seperator)
|
||||||
|
|
@ -94,7 +94,7 @@ TEST(CsvWriter, non_default_seperator)
|
||||||
writer.nextRow();
|
writer.nextRow();
|
||||||
|
|
||||||
QString expected = QString::fromUtf8("1\thel,lo\n");
|
QString expected = QString::fromUtf8("1\thel,lo\n");
|
||||||
ASSERT_THAT(result, Eq(expected));
|
ASSERT_EQ(result, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(CsvWriter, non_default_quote)
|
TEST(CsvWriter, non_default_quote)
|
||||||
|
|
@ -109,5 +109,5 @@ TEST(CsvWriter, non_default_quote)
|
||||||
writer.nextRow();
|
writer.nextRow();
|
||||||
|
|
||||||
QString expected = QString::fromUtf8("1\t*hel\tlo*\n");
|
QString expected = QString::fromUtf8("1\t*hel\tlo*\n");
|
||||||
ASSERT_THAT(result, Eq(expected));
|
ASSERT_EQ(result, expected);
|
||||||
}
|
}
|
||||||
|
|
@ -11,7 +11,7 @@ TEST(PasswordManager, initial_changeMasterPassword_returns_true)
|
||||||
|
|
||||||
auto res = pwm.changeMasterPassword("", "my test passphrase");
|
auto res = pwm.changeMasterPassword("", "my test passphrase");
|
||||||
ASSERT_NO_THROW( res.get() );
|
ASSERT_NO_THROW( res.get() );
|
||||||
ASSERT_THAT( res.get(), Eq(true) );
|
ASSERT_TRUE(res.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(PasswordManager, unlock_succeeds)
|
TEST(PasswordManager, unlock_succeeds)
|
||||||
|
|
@ -22,11 +22,11 @@ TEST(PasswordManager, unlock_succeeds)
|
||||||
|
|
||||||
auto res = pwm.changeMasterPassword("", passphrase);
|
auto res = pwm.changeMasterPassword("", passphrase);
|
||||||
ASSERT_NO_THROW( res.get() );
|
ASSERT_NO_THROW( res.get() );
|
||||||
ASSERT_THAT( res.get(), Eq(true) );
|
ASSERT_TRUE(res.get());
|
||||||
|
|
||||||
auto res2 = pwm.unlock(passphrase);
|
auto res2 = pwm.unlock(passphrase);
|
||||||
ASSERT_NO_THROW( res2.get() );
|
ASSERT_NO_THROW( res2.get() );
|
||||||
ASSERT_THAT( res2.get(), Eq(true) );
|
ASSERT_TRUE(res2.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(PasswordManager, unlock_fails)
|
TEST(PasswordManager, unlock_fails)
|
||||||
|
|
@ -36,12 +36,12 @@ TEST(PasswordManager, unlock_fails)
|
||||||
std::string passphrase = "my test passphrase";
|
std::string passphrase = "my test passphrase";
|
||||||
|
|
||||||
auto res = pwm.changeMasterPassword("", passphrase);
|
auto res = pwm.changeMasterPassword("", passphrase);
|
||||||
ASSERT_NO_THROW( res.get() );
|
ASSERT_NO_THROW(res.get());
|
||||||
ASSERT_THAT( res.get(), Eq(true) );
|
ASSERT_TRUE(res.get());
|
||||||
|
|
||||||
auto res2 = pwm.unlock(passphrase + "2");
|
auto res2 = pwm.unlock(passphrase + "2");
|
||||||
ASSERT_NO_THROW( res2.get() );
|
ASSERT_NO_THROW(res2.get());
|
||||||
ASSERT_THAT( res2.get(), Eq(false) );
|
ASSERT_FALSE(res2.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(PasswordManager, test_save_get)
|
TEST(PasswordManager, test_save_get)
|
||||||
|
|
@ -52,7 +52,7 @@ TEST(PasswordManager, test_save_get)
|
||||||
|
|
||||||
auto res = pwm.changeMasterPassword("", passphrase);
|
auto res = pwm.changeMasterPassword("", passphrase);
|
||||||
ASSERT_NO_THROW( res.get() );
|
ASSERT_NO_THROW( res.get() );
|
||||||
ASSERT_THAT( res.get(), Eq(true) );
|
ASSERT_TRUE(res.get());
|
||||||
|
|
||||||
// auto res2 = pwm.unlock(passphrase + "2");
|
// auto res2 = pwm.unlock(passphrase + "2");
|
||||||
// ASSERT_NO_THROW( res2.get() );
|
// ASSERT_NO_THROW( res2.get() );
|
||||||
|
|
@ -62,12 +62,11 @@ TEST(PasswordManager, test_save_get)
|
||||||
const std::string key = "abc";
|
const std::string key = "abc";
|
||||||
|
|
||||||
auto res2 = pwm.savePassword(key, password);
|
auto res2 = pwm.savePassword(key, password);
|
||||||
ASSERT_THAT( res2.valid(), Eq(true) );
|
ASSERT_TRUE(res2.valid());
|
||||||
|
|
||||||
std::string result;
|
std::string result;
|
||||||
auto res3 = pwm.getPassword(key, result);
|
auto res3 = pwm.getPassword(key, result);
|
||||||
ASSERT_THAT( res3.valid(), Eq(true) );
|
ASSERT_TRUE(res3.valid());
|
||||||
ASSERT_THAT( res3.get(), Eq(true) );
|
ASSERT_TRUE(res3.get());
|
||||||
ASSERT_THAT( result, Eq(password) );
|
ASSERT_EQ(result, password);
|
||||||
|
|
||||||
}
|
}
|
||||||
38
src/core/test/tst_SqlLexer.cpp
Normal file
38
src/core/test/tst_SqlLexer.cpp
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <gmock/gmock-matchers.h>
|
||||||
|
#include "SqlLexer.h"
|
||||||
|
|
||||||
|
using namespace testing;
|
||||||
|
|
||||||
|
|
||||||
|
TEST(SqlLexer, lexer)
|
||||||
|
{
|
||||||
|
QString input = " SELECT ";
|
||||||
|
SqlLexer lexer(input, LexerState::Null);
|
||||||
|
|
||||||
|
int startpos, length;
|
||||||
|
BasicTokenType tokentype;
|
||||||
|
QString out;
|
||||||
|
lexer.nextBasicToken(startpos, length, tokentype, out);
|
||||||
|
|
||||||
|
ASSERT_EQ(startpos, 1);
|
||||||
|
ASSERT_EQ(length, 6);
|
||||||
|
ASSERT_EQ(tokentype, BasicTokenType::Symbol);
|
||||||
|
ASSERT_EQ( out, QString("SELECT") );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SqlLexer, lexer_quote_in_string)
|
||||||
|
{
|
||||||
|
QString input = " 'abc''def' ";
|
||||||
|
SqlLexer lexer(input, LexerState::Null);
|
||||||
|
|
||||||
|
int startpos, length;
|
||||||
|
BasicTokenType tokentype;
|
||||||
|
QString out;
|
||||||
|
lexer.nextBasicToken(startpos, length, tokentype, out);
|
||||||
|
|
||||||
|
ASSERT_EQ(startpos, 1);
|
||||||
|
ASSERT_EQ(length, 10);
|
||||||
|
ASSERT_EQ(tokentype, BasicTokenType::QuotedString);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -9,25 +9,33 @@ Expected<int> getAnswerToEverything() { return 42; }
|
||||||
TEST(expected, valid_when_valid_returns_true)
|
TEST(expected, valid_when_valid_returns_true)
|
||||||
{
|
{
|
||||||
Expected<int> v = getAnswerToEverything();
|
Expected<int> v = getAnswerToEverything();
|
||||||
ASSERT_THAT(v.valid(), Eq(true));
|
ASSERT_TRUE(v.valid());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(expected, get_when_valid_returns_value)
|
TEST(expected, get_when_valid_returns_value)
|
||||||
{
|
{
|
||||||
Expected<int> v = getAnswerToEverything();
|
Expected<int> v = getAnswerToEverything();
|
||||||
ASSERT_THAT(v.get(), Eq(42));
|
ASSERT_EQ(v.get(), 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(expected, get_when_valid_returns_value_copycon)
|
||||||
|
{
|
||||||
|
Expected<int> t = getAnswerToEverything();
|
||||||
|
Expected<int> v(t);
|
||||||
|
ASSERT_TRUE(v.valid());
|
||||||
|
ASSERT_EQ(v.get(), 42);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(expected, hasException_when_valid_returns_false)
|
TEST(expected, hasException_when_valid_returns_false)
|
||||||
{
|
{
|
||||||
Expected<int> v = getAnswerToEverything();
|
Expected<int> v = getAnswerToEverything();
|
||||||
ASSERT_THAT(v.hasException<std::exception>(), Eq(false));
|
ASSERT_FALSE(v.hasException<std::exception>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(expected, T_fromException_is_not_valid)
|
TEST(expected, T_fromException_is_not_valid)
|
||||||
{
|
{
|
||||||
auto e = Expected<int>::fromException(std::runtime_error("hello"));
|
auto e = Expected<int>::fromException(std::runtime_error("hello"));
|
||||||
ASSERT_THAT(e.valid(), Eq(false));
|
ASSERT_FALSE(e.valid());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(expected, T_fromException_get_thows)
|
TEST(expected, T_fromException_get_thows)
|
||||||
|
|
@ -36,41 +44,48 @@ TEST(expected, T_fromException_get_thows)
|
||||||
ASSERT_THROW (e.get(), std::runtime_error);
|
ASSERT_THROW (e.get(), std::runtime_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(expected, T_fromException_get_thows_copycon)
|
||||||
|
{
|
||||||
|
auto f = Expected<int>::fromException(std::runtime_error("hello"));
|
||||||
|
auto e(f);
|
||||||
|
ASSERT_THROW (e.get(), std::runtime_error);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(expected, T_fromException_has_exception_true)
|
TEST(expected, T_fromException_has_exception_true)
|
||||||
{
|
{
|
||||||
auto e = Expected<int>::fromException(std::runtime_error("hello"));
|
auto e = Expected<int>::fromException(std::runtime_error("hello"));
|
||||||
ASSERT_THAT(e.hasException<std::runtime_error>(), Eq(true));
|
ASSERT_TRUE(e.hasException<std::runtime_error>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(expected, T_fromException_has_exception_false)
|
TEST(expected, T_fromException_has_exception_false)
|
||||||
{
|
{
|
||||||
auto e = Expected<int>::fromException(std::runtime_error("hello"));
|
auto e = Expected<int>::fromException(std::runtime_error("hello"));
|
||||||
ASSERT_THAT(e.hasException<std::logic_error>(), Eq(false));
|
ASSERT_FALSE(e.hasException<std::logic_error>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(expected, T_fromException_has_derived_exception)
|
TEST(expected, T_fromException_has_derived_exception)
|
||||||
{
|
{
|
||||||
auto e = Expected<int>::fromException(std::runtime_error("hello"));
|
auto e = Expected<int>::fromException(std::runtime_error("hello"));
|
||||||
ASSERT_THAT(e.hasException<std::exception>(), Eq(true));
|
ASSERT_TRUE(e.hasException<std::exception>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(expected, T_fromCode_is_valid)
|
TEST(expected, T_fromCode_is_valid)
|
||||||
{
|
{
|
||||||
auto e = Expected<int>::fromCode([]() -> int { return 42; });
|
auto e = Expected<int>::fromCode([]() -> int { return 42; });
|
||||||
ASSERT_THAT(e.valid(), Eq(true));
|
ASSERT_TRUE(e.valid());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(expected, T_fromCode_get)
|
TEST(expected, T_fromCode_get)
|
||||||
{
|
{
|
||||||
auto e = Expected<int>::fromCode([]() -> int { return 42; });
|
auto e = Expected<int>::fromCode([]() -> int { return 42; });
|
||||||
ASSERT_THAT(e.get(), Eq(42));
|
ASSERT_EQ(e.get(), 42);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST(expected, T_fromCode_E_is_not_valid)
|
TEST(expected, T_fromCode_E_is_not_valid)
|
||||||
{
|
{
|
||||||
auto e = Expected<int>::fromCode([]() -> int { throw std::runtime_error("hello"); });
|
auto e = Expected<int>::fromCode([]() -> int { throw std::runtime_error("hello"); });
|
||||||
ASSERT_THAT(e.valid(), Eq(false));
|
ASSERT_FALSE(e.valid());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(expected, T_fromCode_E_get_thows)
|
TEST(expected, T_fromCode_E_get_thows)
|
||||||
|
|
@ -82,21 +97,24 @@ TEST(expected, T_fromCode_E_get_thows)
|
||||||
TEST(expected, T_fromCode_E_has_exception_true)
|
TEST(expected, T_fromCode_E_has_exception_true)
|
||||||
{
|
{
|
||||||
auto e = Expected<int>::fromCode([]() -> int { throw std::runtime_error("hello"); });
|
auto e = Expected<int>::fromCode([]() -> int { throw std::runtime_error("hello"); });
|
||||||
ASSERT_THAT(e.hasException<std::runtime_error>(), Eq(true));
|
ASSERT_TRUE(e.hasException<std::runtime_error>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(expected, T_fromCode_E_has_exception_false)
|
TEST(expected, T_fromCode_E_has_exception_false)
|
||||||
{
|
{
|
||||||
auto e = Expected<int>::fromCode([]() -> int { throw std::runtime_error("hello"); });
|
auto e = Expected<int>::fromCode([]() -> int { throw std::runtime_error("hello"); });
|
||||||
ASSERT_THAT(e.hasException<std::logic_error>(), Eq(false));
|
ASSERT_FALSE(e.hasException<std::logic_error>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(expected, T_fromCode_E_has_derived_exception)
|
TEST(expected, T_fromCode_E_has_derived_exception)
|
||||||
{
|
{
|
||||||
auto e = Expected<int>::fromCode([]() -> int { throw std::runtime_error("hello"); });
|
auto e = Expected<int>::fromCode([]() -> int { throw std::runtime_error("hello"); });
|
||||||
ASSERT_THAT(e.hasException<std::exception>(), Eq(true));
|
ASSERT_TRUE(e.hasException<std::exception>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//Expected<int> getIntWithStdRuntimeError() { return Expected<void>(); }
|
//Expected<int> getIntWithStdRuntimeError() { return Expected<void>(); }
|
||||||
|
|
||||||
Expected<void> getNothing() { return Expected<void>(); }
|
Expected<void> getNothing() { return Expected<void>(); }
|
||||||
|
|
@ -105,7 +123,7 @@ Expected<void> getNothing() { return Expected<void>(); }
|
||||||
TEST(expected_void, valid_when_valid_returns_true)
|
TEST(expected_void, valid_when_valid_returns_true)
|
||||||
{
|
{
|
||||||
Expected<void> v = getNothing();
|
Expected<void> v = getNothing();
|
||||||
ASSERT_THAT(v.valid(), Eq(true));
|
ASSERT_TRUE(v.valid());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(expected_void, get_when_valid_returns_value)
|
TEST(expected_void, get_when_valid_returns_value)
|
||||||
|
|
@ -114,17 +132,20 @@ TEST(expected_void, get_when_valid_returns_value)
|
||||||
ASSERT_NO_THROW(v.get());
|
ASSERT_NO_THROW(v.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(expected_void, get_when_valid_returns_value_copycon)
|
||||||
|
{
|
||||||
|
Expected<void> t = getNothing();
|
||||||
|
auto v(t);
|
||||||
|
ASSERT_TRUE(v.valid());
|
||||||
|
ASSERT_NO_THROW(v.get());
|
||||||
|
}
|
||||||
|
|
||||||
TEST(expected_void, hasException_when_valid_returns_false)
|
TEST(expected_void, hasException_when_valid_returns_false)
|
||||||
{
|
{
|
||||||
Expected<void> v = getNothing();
|
Expected<void> v = getNothing();
|
||||||
ASSERT_THAT(v.hasException<std::exception>(), Eq(false));
|
ASSERT_FALSE(v.hasException<std::exception>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
TEST(expected_void, void_fromException_is_not_valid)
|
TEST(expected_void, void_fromException_is_not_valid)
|
||||||
{
|
{
|
||||||
auto e = Expected<void>::fromException(std::runtime_error("hello"));
|
auto e = Expected<void>::fromException(std::runtime_error("hello"));
|
||||||
|
|
@ -201,3 +222,5 @@ TEST(expected_void, void_fromCode_E_has_derived_exception)
|
||||||
auto e = Expected<void>::fromCode(expected_void_throws_func);
|
auto e = Expected<void>::fromCode(expected_void_throws_func);
|
||||||
ASSERT_THAT(e.hasException<std::exception>(), Eq(true));
|
ASSERT_THAT(e.hasException<std::exception>(), Eq(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -9,7 +9,7 @@ TEST(ScopeGuard, normal_run_fun_on_destruction_1)
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
auto sg = scopeGuard([&result]() { result = true; });
|
auto sg = scopeGuard([&result]() { result = true; });
|
||||||
ASSERT_THAT(result, Eq(false));
|
ASSERT_FALSE(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ScopeGuard, normal_run_fun_on_destruction_2)
|
TEST(ScopeGuard, normal_run_fun_on_destruction_2)
|
||||||
|
|
@ -19,7 +19,7 @@ TEST(ScopeGuard, normal_run_fun_on_destruction_2)
|
||||||
auto sg = scopeGuard([&result]() { result = true; });
|
auto sg = scopeGuard([&result]() { result = true; });
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_THAT(result, Eq(true));
|
ASSERT_TRUE(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ScopeGuard, dismiss)
|
TEST(ScopeGuard, dismiss)
|
||||||
|
|
@ -30,7 +30,7 @@ TEST(ScopeGuard, dismiss)
|
||||||
sg.dismiss();
|
sg.dismiss();
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_THAT(result, Eq(false));
|
ASSERT_FALSE(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ScopeGuard, SCOPE_EXIT_macro_1)
|
TEST(ScopeGuard, SCOPE_EXIT_macro_1)
|
||||||
|
|
@ -38,7 +38,7 @@ TEST(ScopeGuard, SCOPE_EXIT_macro_1)
|
||||||
bool result = false;
|
bool result = false;
|
||||||
{
|
{
|
||||||
SCOPE_EXIT { result = true; };
|
SCOPE_EXIT { result = true; };
|
||||||
ASSERT_THAT(result, Eq(false)); // prove previous statement hasn't run yet
|
ASSERT_FALSE(result); // prove previous statement hasn't run yet
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -50,7 +50,7 @@ TEST(ScopeGuard, SCOPE_EXIT_macro_2)
|
||||||
SCOPE_EXIT { result = true; };
|
SCOPE_EXIT { result = true; };
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_THAT(result, Eq(true));
|
ASSERT_TRUE(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.3 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.1 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.4 KiB |
0
src/.gitignore → src/pglab/.gitignore
vendored
0
src/.gitignore → src/pglab/.gitignore
vendored
174
src/pglab/ASyncDBConnection.cpp
Normal file
174
src/pglab/ASyncDBConnection.cpp
Normal file
|
|
@ -0,0 +1,174 @@
|
||||||
|
#include "ASyncDBConnection.h"
|
||||||
|
#include "ScopeGuard.h"
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
using namespace boost::asio;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class registerMetaTypes {
|
||||||
|
public:
|
||||||
|
registerMetaTypes()
|
||||||
|
{
|
||||||
|
qRegisterMetaType<ASyncDBConnection::State>();
|
||||||
|
qRegisterMetaType<Pgsql::ErrorDetails>();
|
||||||
|
}
|
||||||
|
} registerMetaTypes_instance;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ASyncDBConnection::ASyncDBConnection(boost::asio::io_service &ios)
|
||||||
|
: m_asioSock(ios)
|
||||||
|
{}
|
||||||
|
|
||||||
|
ASyncDBConnection::~ASyncDBConnection() = default;
|
||||||
|
|
||||||
|
ASyncDBConnection::State ASyncDBConnection::state() const
|
||||||
|
{
|
||||||
|
return m_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASyncDBConnection::setupConnection(const ConnectionConfig &config)
|
||||||
|
{
|
||||||
|
m_config = config;
|
||||||
|
auto keywords = m_config.getKeywords();
|
||||||
|
auto values = m_config.getValues();
|
||||||
|
|
||||||
|
bool ok = m_connection.connectStart(keywords, values);
|
||||||
|
// auto start = std::chrono::steady_clock::now();
|
||||||
|
if (ok && m_connection.status() != CONNECTION_BAD) {
|
||||||
|
auto sock_handle = m_connection.socket();
|
||||||
|
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); }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASyncDBConnection::async_connect_handler(boost::system::error_code ec, std::size_t s)
|
||||||
|
{
|
||||||
|
// 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); }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASyncDBConnection::doStateCallback(State state)
|
||||||
|
{
|
||||||
|
m_state = state;
|
||||||
|
if (state == State::Connected) {
|
||||||
|
m_canceller = m_connection.getCancel();
|
||||||
|
m_connection.setNoticeReceiver(
|
||||||
|
[this](const PGresult *result) { processNotice(result); });
|
||||||
|
}
|
||||||
|
emit onStateChanged(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void ASyncDBConnection::closeConnection()
|
||||||
|
{
|
||||||
|
// SHould this be async too????
|
||||||
|
if (m_state == State::QuerySend) {
|
||||||
|
m_canceller.cancel(nullptr);
|
||||||
|
}
|
||||||
|
if (m_state != State::NotConnected) {
|
||||||
|
m_asioSock.close();
|
||||||
|
m_connection.close();
|
||||||
|
}
|
||||||
|
doStateCallback(State::NotConnected);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ASyncDBConnection::send(const std::string &command, on_result_callback on_result)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASyncDBConnection::async_query_handler(boost::system::error_code ec, std::size_t s, on_result_callback on_result)
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
on_result(res, ms);
|
||||||
|
if (res == nullptr) {
|
||||||
|
m_timer.invalidate();
|
||||||
|
doStateCallback(State::Connected);
|
||||||
|
finished = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// else is still waiting for more data
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// error during consume
|
||||||
|
auto error_msg = m_connection.getErrorMessage();
|
||||||
|
|
||||||
|
}
|
||||||
|
//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); }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ASyncDBConnection::cancel()
|
||||||
|
{
|
||||||
|
return m_canceller.cancel(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ASyncDBConnection::processNotice(const PGresult *result)
|
||||||
|
{
|
||||||
|
Pgsql::ErrorDetails details = Pgsql::ErrorDetails::createErrorDetailsFromPGresult(result);
|
||||||
|
emit onNotice(details);
|
||||||
|
}
|
||||||
76
src/pglab/ASyncDBConnection.h
Normal file
76
src/pglab/ASyncDBConnection.h
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
#ifndef ASYNCDBCONNECTION_H
|
||||||
|
#define ASYNCDBCONNECTION_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include "Pgsql_Connection.h"
|
||||||
|
#include "Pgsql_Params.h"
|
||||||
|
#include "Pgsql_Result.h"
|
||||||
|
#include "Expected.h"
|
||||||
|
#include "ConnectionConfig.h"
|
||||||
|
#include <QElapsedTimer>
|
||||||
|
#include <mutex>
|
||||||
|
#include <boost/asio/ip/tcp.hpp>
|
||||||
|
#include <boost/asio/io_service.hpp>
|
||||||
|
|
||||||
|
/** \brief Class that handles asynchronous execution of queries.
|
||||||
|
*
|
||||||
|
* Queries are passed to this class with a routine to call on completion
|
||||||
|
* when the result is on that routine is called.
|
||||||
|
*/
|
||||||
|
class ASyncDBConnection: public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
enum class State {
|
||||||
|
NotConnected,
|
||||||
|
Connecting,
|
||||||
|
Connected, ///< connected and idle
|
||||||
|
QuerySend, ///< connected query send expecting result
|
||||||
|
CancelSend, ///< cancel send expecting result
|
||||||
|
Terminating ///< shutting down
|
||||||
|
};
|
||||||
|
|
||||||
|
using on_result_callback = std::function<void(Expected<std::shared_ptr<Pgsql::Result>>, qint64)>;
|
||||||
|
|
||||||
|
explicit ASyncDBConnection(boost::asio::io_service &ios);
|
||||||
|
~ASyncDBConnection();
|
||||||
|
|
||||||
|
State state() const;
|
||||||
|
void setupConnection(const ConnectionConfig &config);
|
||||||
|
void closeConnection();
|
||||||
|
|
||||||
|
/** Sends command to the server.
|
||||||
|
|
||||||
|
When the result is in on_result will be called directly within the thread.
|
||||||
|
|
||||||
|
If the command gives multiple results on_result will be called for each result.
|
||||||
|
*/
|
||||||
|
bool send(const std::string &command, on_result_callback on_result);
|
||||||
|
bool send(const std::string &command, Pgsql::Params params, on_result_callback on_result);
|
||||||
|
|
||||||
|
bool cancel();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void onStateChanged(ASyncDBConnection::State state);
|
||||||
|
void onNotice(Pgsql::ErrorDetails notice);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Pgsql::Connection m_connection;
|
||||||
|
boost::asio::ip::tcp::socket m_asioSock;
|
||||||
|
ConnectionConfig m_config;
|
||||||
|
State m_state = State::NotConnected;
|
||||||
|
Pgsql::Canceller m_canceller;
|
||||||
|
|
||||||
|
QElapsedTimer m_timer;
|
||||||
|
|
||||||
|
void async_connect_handler(boost::system::error_code ec, std::size_t s);
|
||||||
|
void async_query_handler(boost::system::error_code ec, std::size_t s, on_result_callback on_result);
|
||||||
|
void doStateCallback(State state);
|
||||||
|
void processNotice(const PGresult *result);
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(ASyncDBConnection::State);
|
||||||
|
Q_DECLARE_METATYPE(Pgsql::ErrorDetails);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // ASYNCDBCONNECTION_H
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
#include "backupdialog.h"
|
#include "BackupDialog.h"
|
||||||
#include "ui_backupdialog.h"
|
#include "ui_BackupDialog.h"
|
||||||
|
|
||||||
#include "BackupFormatModel.h"
|
#include "BackupFormatModel.h"
|
||||||
|
|
||||||
|
|
@ -9,8 +9,6 @@
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
BackupDialog::BackupDialog(QWidget *parent) :
|
BackupDialog::BackupDialog(QWidget *parent) :
|
||||||
QDialog(parent),
|
QDialog(parent),
|
||||||
ui(new Ui::BackupDialog)
|
ui(new Ui::BackupDialog)
|
||||||
|
|
@ -172,7 +170,8 @@ void BackupDialog::on_btnStart_clicked()
|
||||||
{
|
{
|
||||||
ui->stdOutput->clear();
|
ui->stdOutput->clear();
|
||||||
|
|
||||||
QString program = R"-(C:\Prog\bigsql\pg96\bin\pg_dump.exe)-";
|
//QString program = R"-(C:\Prog\bigsql\pg96\bin\pg_dump.exe)-";
|
||||||
|
QString program = "/usr/bin/pg_dump";
|
||||||
QStringList arguments;
|
QStringList arguments;
|
||||||
setParams(arguments);
|
setParams(arguments);
|
||||||
|
|
||||||
|
|
@ -230,17 +229,18 @@ void BackupDialog::on_btnStart_clicked()
|
||||||
// We use the systemEnvironment as a sane default. Then we let the connection overwrite all PG variables in it.
|
// We use the systemEnvironment as a sane default. Then we let the connection overwrite all PG variables in it.
|
||||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||||
m_config.writeToEnvironment(env);
|
m_config.writeToEnvironment(env);
|
||||||
env.insert("SESSIONNAME", "Console");
|
//env.insert("SESSIONNAME", "Console");
|
||||||
auto p = new QProcess(this);
|
auto p = new QProcess(this);
|
||||||
ConnectTo(p);
|
ConnectTo(p);
|
||||||
p->setProcessEnvironment(env);
|
p->setProcessEnvironment(env);
|
||||||
|
#ifdef WIN32
|
||||||
p->setCreateProcessArgumentsModifier([] (QProcess::CreateProcessArguments *args)
|
p->setCreateProcessArgumentsModifier([] (QProcess::CreateProcessArguments *args)
|
||||||
{
|
{
|
||||||
args->flags |= CREATE_NEW_CONSOLE;
|
args->flags |= CREATE_NEW_CONSOLE;
|
||||||
args->flags &= ~DETACHED_PROCESS;
|
args->flags &= ~DETACHED_PROCESS;
|
||||||
args->startupInfo->dwFlags &= ~STARTF_USESTDHANDLES;
|
args->startupInfo->dwFlags &= ~STARTF_USESTDHANDLES;
|
||||||
});
|
});
|
||||||
|
#endif
|
||||||
p->start(program, arguments);
|
p->start(program, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
#include <QProcessEnvironment>
|
#include <QProcessEnvironment>
|
||||||
#include "connectionconfig.h"
|
#include "ConnectionConfig.h"
|
||||||
|
|
||||||
void setupEnvironment(const ConnectionConfig &cc)
|
void setupEnvironment(const ConnectionConfig &cc)
|
||||||
{
|
{
|
||||||
68
src/pglab/CMakeLists.txt
Normal file
68
src/pglab/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
cmake_minimum_required(VERSION 3.2)
|
||||||
|
project(pglab)
|
||||||
|
|
||||||
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
set(CMAKE_AUTOUIC ON)
|
||||||
|
set(CMAKE_AUTORCC ON)
|
||||||
|
|
||||||
|
add_executable(pglab
|
||||||
|
ASyncDBConnection.cpp
|
||||||
|
ASyncWindow.cpp
|
||||||
|
BackupDialog.cpp
|
||||||
|
BackupRestore.cpp
|
||||||
|
ConnectionConfig.cpp
|
||||||
|
ConnectionList.cpp
|
||||||
|
ConnectionListModel.cpp
|
||||||
|
ConnectionManagerWindow.cpp
|
||||||
|
DatabaseInspectorWidget.cpp
|
||||||
|
DatabasesTableModel.cpp
|
||||||
|
DatabaseWindow.cpp
|
||||||
|
ExplainTreeModelItem.cpp
|
||||||
|
GlobalIoService.cpp
|
||||||
|
jsoncpp.cpp
|
||||||
|
main.cpp
|
||||||
|
MainWindow.cpp
|
||||||
|
MasterController.cpp
|
||||||
|
OpenDatabase.cpp
|
||||||
|
ParamListModel.cpp
|
||||||
|
ParamTypeDelegate.cpp
|
||||||
|
PgAuthIdContainer.cpp
|
||||||
|
PgAuthId.cpp
|
||||||
|
PgClass.cpp
|
||||||
|
PgDatabaseCatalogue.cpp
|
||||||
|
PgDatabaseContainer.cpp
|
||||||
|
PgDatabase.cpp
|
||||||
|
PgNamespace.cpp
|
||||||
|
PgTypeContainer.cpp
|
||||||
|
PgType.cpp
|
||||||
|
ProcessStdioWidget.cpp
|
||||||
|
QueryExplainModel.cpp
|
||||||
|
QueryResultModel.cpp
|
||||||
|
QueryTab.cpp
|
||||||
|
RolesTableModel.cpp
|
||||||
|
ServerWindow.cpp
|
||||||
|
SqlSyntaxHighlighter.cpp
|
||||||
|
stopwatch.cpp
|
||||||
|
tsqueue.cpp
|
||||||
|
tuplesresultwidget.cpp
|
||||||
|
TypeSelectionItemModel.cpp
|
||||||
|
util.cpp
|
||||||
|
resources.qrc
|
||||||
|
)
|
||||||
|
|
||||||
|
set_target_properties(pglab PROPERTIES
|
||||||
|
CXX_STANDARD 14
|
||||||
|
CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||||
|
# target_compile_options(pglab PRIVATE -Wall -fpic -march=native )
|
||||||
|
# set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Og")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_link_libraries( pglab
|
||||||
|
core
|
||||||
|
pgsql
|
||||||
|
boost-system
|
||||||
|
Qt5::Widgets
|
||||||
|
pthread
|
||||||
|
)
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#include "connectionconfig.h"
|
#include "ConnectionConfig.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QProcessEnvironment>
|
#include <QProcessEnvironment>
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
#include "ConnectionList.h"
|
#include "ConnectionList.h"
|
||||||
#include "scopeguard.h"
|
#include "ScopeGuard.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#include "ConnectionListModel.h"
|
#include "ConnectionListModel.h"
|
||||||
#include "ConnectionList.h"
|
#include "ConnectionList.h"
|
||||||
#include "scopeguard.h"
|
#include "ScopeGuard.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#include <botan/cryptobox.h>
|
#include <botan/cryptobox.h>
|
||||||
|
|
@ -6,8 +6,8 @@
|
||||||
|
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
|
|
||||||
#include "connectionconfig.h"
|
#include "ConnectionConfig.h"
|
||||||
#include "expected.h"
|
#include "Expected.h"
|
||||||
|
|
||||||
class ConnectionList;
|
class ConnectionList;
|
||||||
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
#include "connectionmanagerwindow.h"
|
#include "ConnectionManagerWindow.h"
|
||||||
#include "ui_connectionmanagerwindow.h"
|
#include "ui_ConnectionManagerWindow.h"
|
||||||
//#include "mainwindow.h"
|
//#include "mainwindow.h"
|
||||||
#include "MasterController.h"
|
#include "MasterController.h"
|
||||||
#include <QDataWidgetMapper>
|
#include <QDataWidgetMapper>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QStandardItemModel>
|
#include <QStandardItemModel>
|
||||||
|
#include "ConnectionListModel.h"
|
||||||
#include "connectionlistmodel.h"
|
|
||||||
|
|
||||||
ConnectionManagerWindow::ConnectionManagerWindow(MasterController *master, QWidget *parent)
|
ConnectionManagerWindow::ConnectionManagerWindow(MasterController *master, QWidget *parent)
|
||||||
: QMainWindow(parent)
|
: QMainWindow(parent)
|
||||||
|
|
@ -201,12 +201,12 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>800</width>
|
<width>800</width>
|
||||||
<height>23</height>
|
<height>24</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QMenu" name="menuFile">
|
<widget class="QMenu" name="menuFile">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>File</string>
|
<string>Fi&le</string>
|
||||||
</property>
|
</property>
|
||||||
<addaction name="actionQuit_application"/>
|
<addaction name="actionQuit_application"/>
|
||||||
</widget>
|
</widget>
|
||||||
|
|
@ -240,7 +240,7 @@
|
||||||
<action name="actionAdd_Connection">
|
<action name="actionAdd_Connection">
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="resources.qrc">
|
<iconset resource="resources.qrc">
|
||||||
<normaloff>:/icons/server_add.png</normaloff>:/icons/server_add.png</iconset>
|
<normaloff>:/icons/add_connection.png</normaloff>:/icons/add_connection.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Add Connection</string>
|
<string>Add Connection</string>
|
||||||
|
|
@ -248,9 +248,9 @@
|
||||||
</action>
|
</action>
|
||||||
<action name="actionDelete_connection">
|
<action name="actionDelete_connection">
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset>
|
<iconset resource="resources.qrc">
|
||||||
<normalon>:/icons/server_delete.png</normalon>
|
<normaloff>:/icons/delete_connection.png</normaloff>
|
||||||
</iconset>
|
<normalon>:/icons/delete_connection.png</normalon>:/icons/delete_connection.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Delete connection</string>
|
<string>Delete connection</string>
|
||||||
|
|
@ -261,8 +261,9 @@
|
||||||
</action>
|
</action>
|
||||||
<action name="actionConnect">
|
<action name="actionConnect">
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="resources.qrc">
|
<iconset>
|
||||||
<normaloff>:/icons/server_go.png</normaloff>:/icons/server_go.png</iconset>
|
<normalon>:/icons/open_query_window.png</normalon>
|
||||||
|
</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Connect</string>
|
<string>Connect</string>
|
||||||
|
|
@ -270,14 +271,14 @@
|
||||||
</action>
|
</action>
|
||||||
<action name="actionQuit_application">
|
<action name="actionQuit_application">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Quit application</string>
|
<string>&Quit application</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionBackup_database">
|
<action name="actionBackup_database">
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset>
|
<iconset resource="resources.qrc">
|
||||||
<normalon>:/icons/backups.png</normalon>
|
<normaloff>:/icons/backup_database.png</normaloff>
|
||||||
</iconset>
|
<normalon>:/icons/backups.png</normalon>:/icons/backup_database.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Backup database</string>
|
<string>Backup database</string>
|
||||||
|
|
@ -286,7 +287,7 @@
|
||||||
<action name="actionManage_server">
|
<action name="actionManage_server">
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset>
|
<iconset>
|
||||||
<normalon>:/icons/server_edit.png</normalon>
|
<normalon>:/icons/manage_server.png</normalon>
|
||||||
</iconset>
|
</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
#include "databaseinspectorwidget.h"
|
#include "DatabaseInspectorWidget.h"
|
||||||
#include "ui_databaseinspectorwidget.h"
|
#include "ui_DatabaseInspectorWidget.h"
|
||||||
|
|
||||||
DatabaseInspectorWidget::DatabaseInspectorWidget(QWidget *parent) :
|
DatabaseInspectorWidget::DatabaseInspectorWidget(QWidget *parent) :
|
||||||
QWidget(parent),
|
QWidget(parent),
|
||||||
|
|
@ -1,28 +1,23 @@
|
||||||
#include "databasewindow.h"
|
#include "DatabaseWindow.h"
|
||||||
#include "ui_databasewindow.h"
|
#include "ui_DatabaseWindow.h"
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
#include "GlobalIoService.h"
|
||||||
|
|
||||||
|
|
||||||
DatabaseWindow::DatabaseWindow(QWidget *parent) :
|
DatabaseWindow::DatabaseWindow(QWidget *parent) :
|
||||||
QMainWindow(parent),
|
QMainWindow(parent),
|
||||||
ui(new Ui::DatabaseWindow)
|
ui(new Ui::DatabaseWindow),
|
||||||
|
m_dbConnection(*getGlobalAsioIoService())
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
m_dbConnection.setStateCallback([this](ASyncDBConnection::State st)
|
connect(&m_dbConnection, &ASyncDBConnection::onStateChanged, this, &DatabaseWindow::connectionStateChanged);
|
||||||
{
|
connect(&m_dbConnection, &ASyncDBConnection::onNotice, this, &DatabaseWindow::receiveNotice);
|
||||||
QueueTask([this, st]() { connectionStateChanged(st); });
|
|
||||||
});
|
|
||||||
|
|
||||||
m_dbConnection.setNoticeCallback([this](Pgsql::ErrorDetails details)
|
|
||||||
{
|
|
||||||
QueueTask([this, details]() { receiveNotice(details); });
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DatabaseWindow::~DatabaseWindow()
|
DatabaseWindow::~DatabaseWindow()
|
||||||
{
|
{
|
||||||
m_dbConnection.closeConnection();
|
m_dbConnection.closeConnection();
|
||||||
m_dbConnection.setStateCallback(nullptr);
|
|
||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef DATABASEWINDOW_H
|
#ifndef DATABASEWINDOW_H
|
||||||
#define DATABASEWINDOW_H
|
#define DATABASEWINDOW_H
|
||||||
|
|
||||||
#include "asyncdbconnection.h"
|
#include "ASyncDBConnection.h"
|
||||||
#include "tsqueue.h"
|
#include "tsqueue.h"
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
#include "DatabasesTableModel.h"
|
#include "DatabasesTableModel.h"
|
||||||
#include "PgsqlDatabaseCatalogue.h"
|
#include "PgDatabaseCatalogue.h"
|
||||||
#include "PgDatabaseContainer.h"
|
#include "PgDatabaseContainer.h"
|
||||||
#include "PgAuthIdContainer.h"
|
#include "PgAuthIdContainer.h"
|
||||||
|
|
||||||
|
|
@ -8,7 +8,7 @@ DatabasesTableModel::DatabasesTableModel(QObject *parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabasesTableModel::setDatabaseList(const PgsqlDatabaseCatalogue* cat)
|
void DatabasesTableModel::setDatabaseList(const PgDatabaseCatalogue* cat)
|
||||||
{
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
m_catalog = cat;
|
m_catalog = cat;
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
#ifndef DATABASESTABLEMODEL_H
|
#ifndef DATABASESTABLEMODEL_H
|
||||||
#define DATABASESTABLEMODEL_H
|
#define DATABASESTABLEMODEL_H
|
||||||
|
|
||||||
#include <QAbstractTableModel>
|
#include <QAbstractTableModel>
|
||||||
|
|
||||||
class PgDatabaseContainer;
|
class PgDatabaseContainer;
|
||||||
class PgsqlDatabaseCatalogue;
|
class PgDatabaseCatalogue;
|
||||||
|
|
||||||
/** Class for displaying the list of databases of a server in a QTableView
|
/** Class for displaying the list of databases of a server in a QTableView
|
||||||
*
|
*
|
||||||
|
|
@ -22,7 +22,7 @@ public:
|
||||||
|
|
||||||
explicit DatabasesTableModel(QObject *parent);
|
explicit DatabasesTableModel(QObject *parent);
|
||||||
|
|
||||||
void setDatabaseList(const PgsqlDatabaseCatalogue* cat);
|
void setDatabaseList(const PgDatabaseCatalogue* cat);
|
||||||
|
|
||||||
// Header:
|
// Header:
|
||||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||||
|
|
@ -34,7 +34,7 @@ public:
|
||||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const PgsqlDatabaseCatalogue *m_catalog = nullptr;
|
const PgDatabaseCatalogue *m_catalog = nullptr;
|
||||||
const PgDatabaseContainer *m_databases = nullptr;
|
const PgDatabaseContainer *m_databases = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#include "explaintreemodelitem.h"
|
#include "ExplainTreeModelItem.h"
|
||||||
#include "json/json.h"
|
#include "json/json.h"
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
7
src/pglab/GlobalIoService.cpp
Normal file
7
src/pglab/GlobalIoService.cpp
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
#include "GlobalIoService.h"
|
||||||
|
|
||||||
|
std::shared_ptr<boost::asio::io_service> getGlobalAsioIoService()
|
||||||
|
{
|
||||||
|
static auto ios = std::make_shared<boost::asio::io_service>();
|
||||||
|
return ios;
|
||||||
|
}
|
||||||
6
src/pglab/GlobalIoService.h
Normal file
6
src/pglab/GlobalIoService.h
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
|
||||||
|
std::shared_ptr<boost::asio::io_service> getGlobalAsioIoService();
|
||||||
|
|
@ -1,17 +1,16 @@
|
||||||
#include "MainWindow.h"
|
#include "MainWindow.h"
|
||||||
#include "ui_mainwindow.h"
|
#include "ui_MainWindow.h"
|
||||||
|
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QTextTable>
|
#include <QTextTable>
|
||||||
#include <QElapsedTimer>
|
#include <QElapsedTimer>
|
||||||
#include <windows.h>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <QCloseEvent>
|
#include <QCloseEvent>
|
||||||
#include <QMetaObject>
|
#include <QMetaObject>
|
||||||
#include <QMetaMethod>
|
#include <QMetaMethod>
|
||||||
#include <querytab.h>
|
#include "QueryTab.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "MasterController.h"
|
#include "MasterController.h"
|
||||||
#include "OpenDatabase.h"
|
#include "OpenDatabase.h"
|
||||||
|
|
@ -132,6 +131,9 @@ void MainWindow::on_actionAbout_triggered()
|
||||||
"\n"
|
"\n"
|
||||||
"Icons by fatcow http://www.fatcow.com/free-icons provided under Creative Commons "
|
"Icons by fatcow http://www.fatcow.com/free-icons provided under Creative Commons "
|
||||||
"attribution 3.0 license\n"
|
"attribution 3.0 license\n"
|
||||||
|
"\n"
|
||||||
|
"More icons by https://icons8.com/ under Creative Commons Attribution-NoDerivs 3.0 Unported "
|
||||||
|
"license."
|
||||||
));
|
));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
#ifndef MAINWINDOW_H
|
#ifndef MAINWINDOW_H
|
||||||
#define MAINWINDOW_H
|
#define MAINWINDOW_H
|
||||||
|
|
||||||
#include "asyncdbconnection.h"
|
#include "ASyncDBConnection.h"
|
||||||
#include "connectionconfig.h"
|
#include "ConnectionConfig.h"
|
||||||
#include "tsqueue.h"
|
#include "tsqueue.h"
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include "ASyncWindow.h"
|
#include "ASyncWindow.h"
|
||||||
#include <QSocketNotifier>
|
#include <QSocketNotifier>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <future>
|
#include <future>
|
||||||
#include "PgsqlConn.h"
|
#include "Pgsql_Connection.h"
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
@ -41,7 +41,7 @@ private:
|
||||||
Ui::MainWindow *ui;
|
Ui::MainWindow *ui;
|
||||||
|
|
||||||
ConnectionConfig m_config;
|
ConnectionConfig m_config;
|
||||||
OpenDatabase *m_database;
|
OpenDatabase *m_database = nullptr;
|
||||||
|
|
||||||
MasterController *m_masterController;
|
MasterController *m_masterController;
|
||||||
|
|
||||||
|
|
@ -45,12 +45,12 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>993</width>
|
<width>993</width>
|
||||||
<height>22</height>
|
<height>24</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QMenu" name="menuTest">
|
<widget class="QMenu" name="menuTest">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>File</string>
|
<string>Fi&le</string>
|
||||||
</property>
|
</property>
|
||||||
<addaction name="actionNew_SQL"/>
|
<addaction name="actionNew_SQL"/>
|
||||||
<addaction name="actionLoad_SQL"/>
|
<addaction name="actionLoad_SQL"/>
|
||||||
|
|
@ -69,7 +69,7 @@
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenu" name="menuQuery">
|
<widget class="QMenu" name="menuQuery">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Query</string>
|
<string>&Query</string>
|
||||||
</property>
|
</property>
|
||||||
<addaction name="actionExecute_SQL"/>
|
<addaction name="actionExecute_SQL"/>
|
||||||
<addaction name="actionExplain"/>
|
<addaction name="actionExplain"/>
|
||||||
|
|
@ -79,7 +79,7 @@
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenu" name="menuView">
|
<widget class="QMenu" name="menuView">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Window</string>
|
<string>Wi&ndow</string>
|
||||||
</property>
|
</property>
|
||||||
<addaction name="actionShow_connection_manager"/>
|
<addaction name="actionShow_connection_manager"/>
|
||||||
</widget>
|
</widget>
|
||||||
|
|
@ -126,7 +126,7 @@
|
||||||
<normaloff>:/icons/folder.png</normaloff>:/icons/folder.png</iconset>
|
<normaloff>:/icons/folder.png</normaloff>:/icons/folder.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Load SQL</string>
|
<string>&Load SQL</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="shortcut">
|
<property name="shortcut">
|
||||||
<string>Ctrl+O</string>
|
<string>Ctrl+O</string>
|
||||||
|
|
@ -138,7 +138,7 @@
|
||||||
<normaloff>:/icons/script_save.png</normaloff>:/icons/script_save.png</iconset>
|
<normaloff>:/icons/script_save.png</normaloff>:/icons/script_save.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Save SQL</string>
|
<string>&Save SQL</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="shortcut">
|
<property name="shortcut">
|
||||||
<string>Ctrl+S</string>
|
<string>Ctrl+S</string>
|
||||||
|
|
@ -150,7 +150,7 @@
|
||||||
<normaloff>:/icons/table_save.png</normaloff>:/icons/table_save.png</iconset>
|
<normaloff>:/icons/table_save.png</normaloff>:/icons/table_save.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Export data</string>
|
<string>&Export data</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionClose">
|
<action name="actionClose">
|
||||||
|
|
@ -160,7 +160,7 @@
|
||||||
</iconset>
|
</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Close</string>
|
<string>&Close</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="shortcut">
|
<property name="shortcut">
|
||||||
<string>Ctrl+F4</string>
|
<string>Ctrl+F4</string>
|
||||||
|
|
@ -168,12 +168,12 @@
|
||||||
</action>
|
</action>
|
||||||
<action name="actionAbout">
|
<action name="actionAbout">
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset>
|
<iconset resource="resources.qrc">
|
||||||
<normalon>:/icons/information.png</normalon>
|
<normaloff>:/icons/about.png</normaloff>
|
||||||
</iconset>
|
<normalon>:/icons/information.png</normalon>:/icons/about.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>About</string>
|
<string>&About</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionExecute_SQL">
|
<action name="actionExecute_SQL">
|
||||||
|
|
@ -183,7 +183,7 @@
|
||||||
</iconset>
|
</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Execute queries</string>
|
<string>&Execute queries</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Execute the (selected) queries</string>
|
<string>Execute the (selected) queries</string>
|
||||||
|
|
@ -199,7 +199,7 @@
|
||||||
</iconset>
|
</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Cancel</string>
|
<string>&Cancel</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="shortcut">
|
<property name="shortcut">
|
||||||
<string>Alt+Pause</string>
|
<string>Alt+Pause</string>
|
||||||
|
|
@ -211,7 +211,7 @@
|
||||||
<normaloff>:/icons/lightbulb.png</normaloff>:/icons/lightbulb.png</iconset>
|
<normaloff>:/icons/lightbulb.png</normaloff>:/icons/lightbulb.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Explain Analyze</string>
|
<string>Ex&plain Analyze</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="shortcut">
|
<property name="shortcut">
|
||||||
<string>Shift+F7</string>
|
<string>Shift+F7</string>
|
||||||
|
|
@ -219,22 +219,22 @@
|
||||||
</action>
|
</action>
|
||||||
<action name="actionSave_SQL_as">
|
<action name="actionSave_SQL_as">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Save SQL as</string>
|
<string>Sa&ve SQL as</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionSave_copy_of_SQL_as">
|
<action name="actionSave_copy_of_SQL_as">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Save copy of SQL as</string>
|
<string>Save copy &of SQL as</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionNew_SQL">
|
<action name="actionNew_SQL">
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset>
|
<iconset resource="resources.qrc">
|
||||||
<normalon>:/icons/page_white_add.png</normalon>
|
<normaloff>:/icons/new_query_tab.png</normaloff>
|
||||||
</iconset>
|
<normalon>:/icons/page_white_add.png</normalon>:/icons/new_query_tab.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>New SQL</string>
|
<string>&New SQL</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="shortcut">
|
<property name="shortcut">
|
||||||
<string>Ctrl+N</string>
|
<string>Ctrl+N</string>
|
||||||
|
|
@ -247,7 +247,7 @@
|
||||||
</iconset>
|
</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Explain</string>
|
<string>E&xplain</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Explain the (selected) query</string>
|
<string>Explain the (selected) query</string>
|
||||||
|
|
@ -258,7 +258,7 @@
|
||||||
</action>
|
</action>
|
||||||
<action name="actionShow_connection_manager">
|
<action name="actionShow_connection_manager">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Show connection manager</string>
|
<string>&Show connection manager</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionCopy">
|
<action name="actionCopy">
|
||||||
|
|
@ -268,7 +268,7 @@
|
||||||
</iconset>
|
</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Copy</string>
|
<string>&Copy</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="shortcut">
|
<property name="shortcut">
|
||||||
<string>Ctrl+C</string>
|
<string>Ctrl+C</string>
|
||||||
|
|
@ -281,7 +281,7 @@
|
||||||
</iconset>
|
</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Copy as C-string</string>
|
<string>Copy as C-&string</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="shortcut">
|
<property name="shortcut">
|
||||||
<string>Ctrl+Alt+C</string>
|
<string>Ctrl+Alt+C</string>
|
||||||
|
|
@ -2,8 +2,10 @@
|
||||||
#define MASTERCONTROLLER_H
|
#define MASTERCONTROLLER_H
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <future>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
|
||||||
class ConnectionConfig;
|
class ConnectionConfig;
|
||||||
class ConnectionList;
|
class ConnectionList;
|
||||||
class ConnectionListModel;
|
class ConnectionListModel;
|
||||||
|
|
@ -39,6 +41,7 @@ private:
|
||||||
ConnectionList *m_connectionList = nullptr;
|
ConnectionList *m_connectionList = nullptr;
|
||||||
ConnectionListModel *m_connectionListModel = nullptr;
|
ConnectionListModel *m_connectionListModel = nullptr;
|
||||||
ConnectionManagerWindow *m_connectionManagerWindow = nullptr;
|
ConnectionManagerWindow *m_connectionManagerWindow = nullptr;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MASTERCONTROLLER_H
|
#endif // MASTERCONTROLLER_H
|
||||||
|
|
@ -1,23 +1,25 @@
|
||||||
#include "OpenDatabase.h"
|
#include "OpenDatabase.h"
|
||||||
#include "pgsqldatabasecatalogue.h"
|
#include "PgDatabaseCatalogue.h"
|
||||||
#include "PgsqlConn.h"
|
#include "Pgsql_Connection.h"
|
||||||
#include "typeselectionitemmodel.h"
|
#include "TypeSelectionItemModel.h"
|
||||||
|
|
||||||
Expected<OpenDatabase*> OpenDatabase::createOpenDatabase(const ConnectionConfig &cfg)
|
Expected<OpenDatabase*> OpenDatabase::createOpenDatabase(const ConnectionConfig &cfg)
|
||||||
{
|
{
|
||||||
OpenDatabase *odb = new OpenDatabase(cfg, nullptr);
|
OpenDatabase *odb = new OpenDatabase(cfg, nullptr);
|
||||||
if (odb->Init()) {
|
if (odb->Init()) {
|
||||||
|
|
||||||
|
return odb;
|
||||||
|
|
||||||
}
|
}
|
||||||
return odb;
|
|
||||||
//return Expected<ConnectionConfig>::fromException(std::out_of_range("Invalid row"));
|
//return Expected<ConnectionConfig>::fromException(std::out_of_range("Invalid row"));
|
||||||
|
return Expected<OpenDatabase*>::fromException(
|
||||||
|
std::runtime_error("Failed to get database information"));
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenDatabase::OpenDatabase(const ConnectionConfig& cfg, QObject *parent)
|
OpenDatabase::OpenDatabase(const ConnectionConfig& cfg, QObject *parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, m_config(cfg)
|
, m_config(cfg)
|
||||||
, m_catalogue(new PgsqlDatabaseCatalogue)
|
, m_catalogue(new PgDatabaseCatalogue)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -33,11 +35,12 @@ bool OpenDatabase::Init()
|
||||||
auto vals = m_config.getValues();
|
auto vals = m_config.getValues();
|
||||||
if (conn.connect(kw, vals, 0)) {
|
if (conn.connect(kw, vals, 0)) {
|
||||||
m_catalogue->loadAll(conn);
|
m_catalogue->loadAll(conn);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
PgsqlDatabaseCatalogue* OpenDatabase::catalogue()
|
PgDatabaseCatalogue* OpenDatabase::catalogue()
|
||||||
{
|
{
|
||||||
return m_catalogue;
|
return m_catalogue;
|
||||||
}
|
}
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
#ifndef OPENDATABASE_H
|
#ifndef OPENDATABASE_H
|
||||||
#define OPENDATABASE_H
|
#define OPENDATABASE_H
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include "connectionconfig.h"
|
#include "ConnectionConfig.h"
|
||||||
#include "expected.h"
|
#include "Expected.h"
|
||||||
|
|
||||||
class PgsqlDatabaseCatalogue;
|
class PgDatabaseCatalogue;
|
||||||
class TypeSelectionItemModel;
|
class TypeSelectionItemModel;
|
||||||
|
|
||||||
/** Instances of this class represent a single database on which atleast one
|
/** Instances of this class represent a single database on which atleast one
|
||||||
|
|
@ -21,7 +21,7 @@ public:
|
||||||
OpenDatabase& operator=(const OpenDatabase &) = delete;
|
OpenDatabase& operator=(const OpenDatabase &) = delete;
|
||||||
~OpenDatabase();
|
~OpenDatabase();
|
||||||
|
|
||||||
PgsqlDatabaseCatalogue* catalogue();
|
PgDatabaseCatalogue* catalogue();
|
||||||
TypeSelectionItemModel* typeSelectionModel();
|
TypeSelectionItemModel* typeSelectionModel();
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
|
|
@ -29,7 +29,7 @@ public slots:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ConnectionConfig m_config;
|
ConnectionConfig m_config;
|
||||||
PgsqlDatabaseCatalogue *m_catalogue;
|
PgDatabaseCatalogue *m_catalogue;
|
||||||
|
|
||||||
TypeSelectionItemModel *m_typeSelectionModel = nullptr;
|
TypeSelectionItemModel *m_typeSelectionModel = nullptr;
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#ifndef PARAMLISTMODEL_H
|
#ifndef PARAMLISTMODEL_H
|
||||||
#define PARAMLISTMODEL_H
|
#define PARAMLISTMODEL_H
|
||||||
|
|
||||||
#include <QAbstractTableModel>
|
#include <QAbstractTableModel>
|
||||||
|
|
@ -11,7 +11,7 @@ public:
|
||||||
class Param {
|
class Param {
|
||||||
public:
|
public:
|
||||||
QString value; ///< the value of the parameter (currently this is passed directly)
|
QString value; ///< the value of the parameter (currently this is passed directly)
|
||||||
QString type = InvalidOid; ///< the type of the parameter
|
QString type; ///< the type of the parameter
|
||||||
|
|
||||||
Param() = default;
|
Param() = default;
|
||||||
Param(const QString &v, const QString t)
|
Param(const QString &v, const QString t)
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef PGAUTHID_H
|
#ifndef PGAUTHID_H
|
||||||
#define PGAUTHID_H
|
#define PGAUTHID_H
|
||||||
|
|
||||||
#include <pgsql/libpq-fe.h>
|
#include <libpq-fe.h>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
#include "PgAuthIdContainer.h"
|
#include "PgAuthIdContainer.h"
|
||||||
#include "PgsqlConn.h"
|
#include "Pgsql_Connection.h"
|
||||||
#include "PgsqlDatabaseCatalogue.h"
|
#include "PgDatabaseCatalogue.h"
|
||||||
|
|
||||||
PgAuthIdContainer::PgAuthIdContainer(PgsqlDatabaseCatalogue *cat)
|
PgAuthIdContainer::PgAuthIdContainer(PgDatabaseCatalogue *cat)
|
||||||
: PgContainer<PgAuthId>(cat)
|
: PgContainer<PgAuthId>(cat)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#ifndef PGAUTHIDCONTAINER_H
|
#ifndef PGAUTHIDCONTAINER_H
|
||||||
#define PGAUTHIDCONTAINER_H
|
#define PGAUTHIDCONTAINER_H
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
@ -14,7 +14,7 @@ namespace Pgsql {
|
||||||
|
|
||||||
class PgAuthIdContainer: public PgContainer<PgAuthId> {
|
class PgAuthIdContainer: public PgContainer<PgAuthId> {
|
||||||
public:
|
public:
|
||||||
explicit PgAuthIdContainer(PgsqlDatabaseCatalogue *cat);
|
explicit PgAuthIdContainer(PgDatabaseCatalogue *cat);
|
||||||
|
|
||||||
std::string getLoadQuery() const;
|
std::string getLoadQuery() const;
|
||||||
void load(const Pgsql::Result &res);
|
void load(const Pgsql::Result &res);
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
#include "pgclass.h"
|
#include "PgClass.h"
|
||||||
|
|
||||||
PgClass::PgClass() = default;
|
PgClass::PgClass() = default;
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
#define PGCLASS_H
|
#define PGCLASS_H
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <pgsql/libpq-fe.h>
|
#include <libpq-fe.h>
|
||||||
|
|
||||||
class PgClass {
|
class PgClass {
|
||||||
public:
|
public:
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
#ifndef PGCONTAINER_H
|
#ifndef PGCONTAINER_H
|
||||||
#define PGCONTAINER_H
|
#define PGCONTAINER_H
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <pgsql/libpq-fe.h>
|
#include <libpq-fe.h>
|
||||||
|
|
||||||
class PgsqlDatabaseCatalogue;
|
class PgDatabaseCatalogue;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class PgContainer {
|
class PgContainer {
|
||||||
public:
|
public:
|
||||||
using t_Container = std::vector<T>; ///< Do not assume it will stay a vector only expect bidirectional access
|
using t_Container = std::vector<T>; ///< Do not assume it will stay a vector only expect bidirectional access
|
||||||
|
|
||||||
explicit PgContainer(PgsqlDatabaseCatalogue *cat)
|
explicit PgContainer(PgDatabaseCatalogue *cat)
|
||||||
: m_catalogue(cat)
|
: m_catalogue(cat)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
@ -60,7 +60,7 @@ public:
|
||||||
return m_container.at(idx);
|
return m_container.at(idx);
|
||||||
}
|
}
|
||||||
protected:
|
protected:
|
||||||
PgsqlDatabaseCatalogue *m_catalogue;
|
PgDatabaseCatalogue *m_catalogue;
|
||||||
t_Container m_container;
|
t_Container m_container;
|
||||||
private:
|
private:
|
||||||
T m_invalidInstance;
|
T m_invalidInstance;
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
#define PGDATABASE_H
|
#define PGDATABASE_H
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <pgsql/libpq-fe.h>
|
#include <libpq-fe.h>
|
||||||
|
|
||||||
class PgDatabase {
|
class PgDatabase {
|
||||||
public:
|
public:
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
#include "PgsqlDatabaseCatalogue.h"
|
#include "PgDatabaseCatalogue.h"
|
||||||
#include "PgTypeContainer.h"
|
#include "PgTypeContainer.h"
|
||||||
#include "PgDatabaseContainer.h"
|
#include "PgDatabaseContainer.h"
|
||||||
#include "PgAuthIdContainer.h"
|
#include "PgAuthIdContainer.h"
|
||||||
#include "PgsqlConn.h"
|
#include "Pgsql_Connection.h"
|
||||||
|
|
||||||
|
|
||||||
QString getRoleNameFromOid(const PgsqlDatabaseCatalogue *cat, Oid oid)
|
QString getRoleNameFromOid(const PgDatabaseCatalogue *cat, Oid oid)
|
||||||
{
|
{
|
||||||
QString name;
|
QString name;
|
||||||
const PgAuthIdContainer *auth_ids = cat->authIds();
|
const PgAuthIdContainer *auth_ids = cat->authIds();
|
||||||
|
|
@ -18,23 +18,23 @@ QString getRoleNameFromOid(const PgsqlDatabaseCatalogue *cat, Oid oid)
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
PgsqlDatabaseCatalogue::PgsqlDatabaseCatalogue()
|
PgDatabaseCatalogue::PgDatabaseCatalogue()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
PgsqlDatabaseCatalogue::~PgsqlDatabaseCatalogue()
|
PgDatabaseCatalogue::~PgDatabaseCatalogue()
|
||||||
{
|
{
|
||||||
delete m_types;
|
delete m_types;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PgsqlDatabaseCatalogue::loadAll(Pgsql::Connection &conn)
|
void PgDatabaseCatalogue::loadAll(Pgsql::Connection &conn)
|
||||||
{
|
{
|
||||||
loadTypes(conn);
|
loadTypes(conn);
|
||||||
loadDatabases(conn);
|
loadDatabases(conn);
|
||||||
loadAuthIds(conn);
|
loadAuthIds(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PgsqlDatabaseCatalogue::loadInfo(Pgsql::Connection &conn)
|
void PgDatabaseCatalogue::loadInfo(Pgsql::Connection &conn)
|
||||||
{
|
{
|
||||||
Pgsql::Result r = conn.query("SHOW server_version_num");
|
Pgsql::Result r = conn.query("SHOW server_version_num");
|
||||||
if (r && r.resultStatus() == PGRES_TUPLES_OK)
|
if (r && r.resultStatus() == PGRES_TUPLES_OK)
|
||||||
|
|
@ -47,7 +47,7 @@ void PgsqlDatabaseCatalogue::loadInfo(Pgsql::Connection &conn)
|
||||||
m_serverVersionString = r.get(0, 0).asQString();
|
m_serverVersionString = r.get(0, 0).asQString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PgsqlDatabaseCatalogue::loadTypes(Pgsql::Connection &conn)
|
void PgDatabaseCatalogue::loadTypes(Pgsql::Connection &conn)
|
||||||
{
|
{
|
||||||
if (m_types == nullptr)
|
if (m_types == nullptr)
|
||||||
m_types = new PgTypeContainer(this);
|
m_types = new PgTypeContainer(this);
|
||||||
|
|
@ -61,7 +61,7 @@ void PgsqlDatabaseCatalogue::loadTypes(Pgsql::Connection &conn)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PgsqlDatabaseCatalogue::loadDatabases(Pgsql::Connection &conn)
|
void PgDatabaseCatalogue::loadDatabases(Pgsql::Connection &conn)
|
||||||
{
|
{
|
||||||
if (m_databases == nullptr)
|
if (m_databases == nullptr)
|
||||||
m_databases = new PgDatabaseContainer(this);
|
m_databases = new PgDatabaseContainer(this);
|
||||||
|
|
@ -75,7 +75,7 @@ void PgsqlDatabaseCatalogue::loadDatabases(Pgsql::Connection &conn)
|
||||||
throw std::runtime_error("Query failed");
|
throw std::runtime_error("Query failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
void PgsqlDatabaseCatalogue::loadAuthIds(Pgsql::Connection &conn)
|
void PgDatabaseCatalogue::loadAuthIds(Pgsql::Connection &conn)
|
||||||
{
|
{
|
||||||
if (m_authIds == nullptr)
|
if (m_authIds == nullptr)
|
||||||
m_authIds = new PgAuthIdContainer(this);
|
m_authIds = new PgAuthIdContainer(this);
|
||||||
|
|
@ -88,27 +88,27 @@ void PgsqlDatabaseCatalogue::loadAuthIds(Pgsql::Connection &conn)
|
||||||
throw std::runtime_error("Query failed");
|
throw std::runtime_error("Query failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString& PgsqlDatabaseCatalogue::serverVersionString() const
|
const QString& PgDatabaseCatalogue::serverVersionString() const
|
||||||
{
|
{
|
||||||
return m_serverVersionString;
|
return m_serverVersionString;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PgsqlDatabaseCatalogue::serverVersion() const
|
int PgDatabaseCatalogue::serverVersion() const
|
||||||
{
|
{
|
||||||
return m_serverVersion;
|
return m_serverVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PgTypeContainer* PgsqlDatabaseCatalogue::types() const
|
const PgTypeContainer* PgDatabaseCatalogue::types() const
|
||||||
{
|
{
|
||||||
return m_types;
|
return m_types;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PgDatabaseContainer *PgsqlDatabaseCatalogue::databases() const
|
const PgDatabaseContainer *PgDatabaseCatalogue::databases() const
|
||||||
{
|
{
|
||||||
return m_databases;
|
return m_databases;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PgAuthIdContainer *PgsqlDatabaseCatalogue::authIds() const
|
const PgAuthIdContainer *PgDatabaseCatalogue::authIds() const
|
||||||
{
|
{
|
||||||
return m_authIds;
|
return m_authIds;
|
||||||
}
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef PGSQLDATABASECATALOGUE_H
|
#ifndef PGSQLDATABASECATALOGUE_H
|
||||||
#define PGSQLDATABASECATALOGUE_H
|
#define PGSQLDATABASECATALOGUE_H
|
||||||
|
|
||||||
#include <pgsql/libpq-fe.h>
|
#include <libpq-fe.h>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
@ -15,13 +15,13 @@ class PgTypeContainer;
|
||||||
class PgDatabaseContainer;
|
class PgDatabaseContainer;
|
||||||
class PgAuthIdContainer;
|
class PgAuthIdContainer;
|
||||||
|
|
||||||
class PgsqlDatabaseCatalogue {
|
class PgDatabaseCatalogue {
|
||||||
public:
|
public:
|
||||||
PgsqlDatabaseCatalogue();
|
PgDatabaseCatalogue();
|
||||||
PgsqlDatabaseCatalogue(const PgsqlDatabaseCatalogue&) = delete;
|
PgDatabaseCatalogue(const PgDatabaseCatalogue&) = delete;
|
||||||
PgsqlDatabaseCatalogue& operator = (const PgsqlDatabaseCatalogue&) = delete;
|
PgDatabaseCatalogue& operator = (const PgDatabaseCatalogue&) = delete;
|
||||||
|
|
||||||
~PgsqlDatabaseCatalogue();
|
~PgDatabaseCatalogue();
|
||||||
|
|
||||||
|
|
||||||
void loadAll(Pgsql::Connection &conn);
|
void loadAll(Pgsql::Connection &conn);
|
||||||
|
|
@ -44,6 +44,6 @@ private:
|
||||||
PgAuthIdContainer *m_authIds = nullptr;
|
PgAuthIdContainer *m_authIds = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
QString getRoleNameFromOid(const PgsqlDatabaseCatalogue *cat, Oid oid);
|
QString getRoleNameFromOid(const PgDatabaseCatalogue *cat, Oid oid);
|
||||||
|
|
||||||
#endif // PGSQLDATABASECATALOGUE_H
|
#endif // PGSQLDATABASECATALOGUE_H
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#include "PgDatabaseContainer.h"
|
#include "PgDatabaseContainer.h"
|
||||||
#include "PgsqlConn.h"
|
#include "Pgsql_Connection.h"
|
||||||
|
|
||||||
PgDatabaseContainer::PgDatabaseContainer(PgsqlDatabaseCatalogue *cat)
|
PgDatabaseContainer::PgDatabaseContainer(PgDatabaseCatalogue *cat)
|
||||||
: PgContainer<PgDatabase>(cat)
|
: PgContainer<PgDatabase>(cat)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#ifndef PGDATABASECONTAINER_H
|
#ifndef PGDATABASECONTAINER_H
|
||||||
#define PGDATABASECONTAINER_H
|
#define PGDATABASECONTAINER_H
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
@ -14,7 +14,7 @@ namespace Pgsql {
|
||||||
|
|
||||||
class PgDatabaseContainer: public PgContainer<PgDatabase> {
|
class PgDatabaseContainer: public PgContainer<PgDatabase> {
|
||||||
public:
|
public:
|
||||||
explicit PgDatabaseContainer(PgsqlDatabaseCatalogue *cat);
|
explicit PgDatabaseContainer(PgDatabaseCatalogue *cat);
|
||||||
|
|
||||||
std::string getLoadQuery() const;
|
std::string getLoadQuery() const;
|
||||||
void load(const Pgsql::Result &res);
|
void load(const Pgsql::Result &res);
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#include "pgnamespace.h"
|
#include "PgNamespace.h"
|
||||||
|
|
||||||
PgNamespace::PgNamespace() = default;
|
PgNamespace::PgNamespace() = default;
|
||||||
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
#define PGNAMESPACE_H
|
#define PGNAMESPACE_H
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <pgsql/libpq-fe.h>
|
#include <libpq-fe.h>
|
||||||
|
|
||||||
class PgNamespace
|
class PgNamespace
|
||||||
{
|
{
|
||||||
5
src/pglab/PgType.cpp
Normal file
5
src/pglab/PgType.cpp
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
#include "PgType.h"
|
||||||
|
#include "Pgsql_Connection.h"
|
||||||
|
|
||||||
|
PgType::PgType() = default;
|
||||||
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
#define PGTYPE_H
|
#define PGTYPE_H
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <pgsql/libpq-fe.h>
|
#include <libpq-fe.h>
|
||||||
|
|
||||||
class PgType {
|
class PgType {
|
||||||
public:
|
public:
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
#include "pgtypecontainer.h"
|
#include "PgTypeContainer.h"
|
||||||
#include "PgsqlConn.h"
|
#include "Pgsql_Connection.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
PgTypeContainer::PgTypeContainer(PgsqlDatabaseCatalogue *cat)
|
PgTypeContainer::PgTypeContainer(PgDatabaseCatalogue *cat)
|
||||||
: PgContainer<PgType>(cat)
|
: PgContainer<PgType>(cat)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
#ifndef PGTYPECONTAINER_H
|
#ifndef PGTYPECONTAINER_H
|
||||||
#define PGTYPECONTAINER_H
|
#define PGTYPECONTAINER_H
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "pgtype.h"
|
#include "PgType.h"
|
||||||
#include "PgContainer.h"
|
#include "PgContainer.h"
|
||||||
|
|
||||||
namespace Pgsql {
|
namespace Pgsql {
|
||||||
|
|
@ -15,7 +15,7 @@ class PgTypeContainer: public PgContainer<PgType> {
|
||||||
public:
|
public:
|
||||||
// using t_Types = std::vector<PgType>; ///< Do not assume it will stay a vector only expect bidirectional access
|
// using t_Types = std::vector<PgType>; ///< Do not assume it will stay a vector only expect bidirectional access
|
||||||
|
|
||||||
explicit PgTypeContainer(PgsqlDatabaseCatalogue *cat);
|
explicit PgTypeContainer(PgDatabaseCatalogue *cat);
|
||||||
|
|
||||||
// t_Types::const_iterator begin() const { return m_types.begin(); }
|
// t_Types::const_iterator begin() const { return m_types.begin(); }
|
||||||
// t_Types::const_iterator end() const { return m_types.end(); }
|
// t_Types::const_iterator end() const { return m_types.end(); }
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#include "queryexplainmodel.h"
|
#include "QueryExplainModel.h"
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
#include <QSize>
|
#include <QSize>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
const int c_ColumnNode = 0;
|
const int c_ColumnNode = 0;
|
||||||
const int c_ColumnExclusive = 1;
|
const int c_ColumnExclusive = 1;
|
||||||
|
|
@ -79,7 +80,7 @@ if (role == Qt::DisplayRole) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (col == c_ColumnEstErr) {
|
if (col == c_ColumnEstErr) {
|
||||||
float e = fabs(item->estimateError());
|
float e = std::fabs(item->estimateError());
|
||||||
if (e > 1000.0f) {
|
if (e > 1000.0f) {
|
||||||
result = QColor(255, 192, 192);
|
result = QColor(255, 192, 192);
|
||||||
}
|
}
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
#include <QAbstractItemModel>
|
#include <QAbstractItemModel>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "explaintreemodelitem.h"
|
#include "ExplainTreeModelItem.h"
|
||||||
|
|
||||||
/** \brief Model class for displaying the explain of a query in a tree like format.
|
/** \brief Model class for displaying the explain of a query in a tree like format.
|
||||||
*/
|
*/
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#include "queryresultmodel.h"
|
#include "QueryResultModel.h"
|
||||||
#include "Pgsql_declare.h"
|
#include "Pgsql_declare.h"
|
||||||
#include <QBrush>
|
#include <QBrush>
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue