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()
|
||||
{}
|
||||
|
|
@ -27,7 +27,7 @@ public:
|
|||
|
||||
|
||||
Expected(const Expected& rhs)
|
||||
: m_valid(rhs.valid)
|
||||
: m_valid(rhs.m_valid)
|
||||
{
|
||||
if (m_valid) {
|
||||
new (&m_value) T(rhs.m_value);
|
||||
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include "Core.h"
|
||||
|
||||
using namespace Botan;
|
||||
|
||||
|
|
@ -29,7 +29,8 @@ QChar SqlLexer::peekChar()
|
|||
* @param ofs
|
||||
* @param start
|
||||
* @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)
|
||||
{
|
||||
|
|
@ -117,6 +118,46 @@ bool SqlLexer::nextBasicToken(int &startpos, int &length, BasicTokenType &tokent
|
|||
else if (c == QChar::Null) {
|
||||
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 {
|
||||
// Undetermined symbol
|
||||
for (;;) {
|
||||
|
|
@ -11,8 +11,9 @@ enum class BasicTokenType {
|
|||
BlockComment,
|
||||
OpenBlockComment, // Busy with a block comment end not detected before end of current input
|
||||
QuotedString,
|
||||
DollarQuotedString,
|
||||
QuotedIdentifier
|
||||
DollarQuote, // Return the dollar quote tag, do not consume the entire string (potentially long)
|
||||
QuotedIdentifier,
|
||||
Parameter
|
||||
};
|
||||
|
||||
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();
|
||||
|
||||
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)
|
||||
|
|
@ -34,7 +34,7 @@ TEST(CsvWriter, one_row_one_number_one_unquoted_string)
|
|||
writer.nextRow();
|
||||
|
||||
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)
|
||||
|
|
@ -49,7 +49,7 @@ TEST(CsvWriter, one_row_one_number_one_quoted_string)
|
|||
writer.nextRow();
|
||||
|
||||
QString expected = QString::fromUtf8("1,\"hel,lo\"\n");
|
||||
ASSERT_THAT(result, Eq(expected));
|
||||
ASSERT_EQ(result, expected);
|
||||
}
|
||||
|
||||
TEST(CsvWriter, newline_in_field)
|
||||
|
|
@ -64,7 +64,7 @@ TEST(CsvWriter, newline_in_field)
|
|||
writer.nextRow();
|
||||
|
||||
QString expected = QString::fromUtf8("1,\"hel\nlo\"\n");
|
||||
ASSERT_THAT(result, Eq(expected));
|
||||
ASSERT_EQ(result, expected);
|
||||
}
|
||||
|
||||
TEST(CsvWriter, escape_quote)
|
||||
|
|
@ -79,7 +79,7 @@ TEST(CsvWriter, escape_quote)
|
|||
writer.nextRow();
|
||||
|
||||
QString expected = QString::fromUtf8("1,\"hel\"\"lo\"\n");
|
||||
ASSERT_THAT(result, Eq(expected));
|
||||
ASSERT_EQ(result, expected);
|
||||
}
|
||||
|
||||
TEST(CsvWriter, non_default_seperator)
|
||||
|
|
@ -94,7 +94,7 @@ TEST(CsvWriter, non_default_seperator)
|
|||
writer.nextRow();
|
||||
|
||||
QString expected = QString::fromUtf8("1\thel,lo\n");
|
||||
ASSERT_THAT(result, Eq(expected));
|
||||
ASSERT_EQ(result, expected);
|
||||
}
|
||||
|
||||
TEST(CsvWriter, non_default_quote)
|
||||
|
|
@ -109,5 +109,5 @@ TEST(CsvWriter, non_default_quote)
|
|||
writer.nextRow();
|
||||
|
||||
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");
|
||||
ASSERT_NO_THROW( res.get() );
|
||||
ASSERT_THAT( res.get(), Eq(true) );
|
||||
ASSERT_TRUE(res.get());
|
||||
}
|
||||
|
||||
TEST(PasswordManager, unlock_succeeds)
|
||||
|
|
@ -22,11 +22,11 @@ TEST(PasswordManager, unlock_succeeds)
|
|||
|
||||
auto res = pwm.changeMasterPassword("", passphrase);
|
||||
ASSERT_NO_THROW( res.get() );
|
||||
ASSERT_THAT( res.get(), Eq(true) );
|
||||
ASSERT_TRUE(res.get());
|
||||
|
||||
auto res2 = pwm.unlock(passphrase);
|
||||
ASSERT_NO_THROW( res2.get() );
|
||||
ASSERT_THAT( res2.get(), Eq(true) );
|
||||
ASSERT_TRUE(res2.get());
|
||||
}
|
||||
|
||||
TEST(PasswordManager, unlock_fails)
|
||||
|
|
@ -36,12 +36,12 @@ TEST(PasswordManager, unlock_fails)
|
|||
std::string passphrase = "my test passphrase";
|
||||
|
||||
auto res = pwm.changeMasterPassword("", passphrase);
|
||||
ASSERT_NO_THROW( res.get() );
|
||||
ASSERT_THAT( res.get(), Eq(true) );
|
||||
ASSERT_NO_THROW(res.get());
|
||||
ASSERT_TRUE(res.get());
|
||||
|
||||
auto res2 = pwm.unlock(passphrase + "2");
|
||||
ASSERT_NO_THROW( res2.get() );
|
||||
ASSERT_THAT( res2.get(), Eq(false) );
|
||||
ASSERT_NO_THROW(res2.get());
|
||||
ASSERT_FALSE(res2.get());
|
||||
}
|
||||
|
||||
TEST(PasswordManager, test_save_get)
|
||||
|
|
@ -52,7 +52,7 @@ TEST(PasswordManager, test_save_get)
|
|||
|
||||
auto res = pwm.changeMasterPassword("", passphrase);
|
||||
ASSERT_NO_THROW( res.get() );
|
||||
ASSERT_THAT( res.get(), Eq(true) );
|
||||
ASSERT_TRUE(res.get());
|
||||
|
||||
// auto res2 = pwm.unlock(passphrase + "2");
|
||||
// ASSERT_NO_THROW( res2.get() );
|
||||
|
|
@ -62,12 +62,11 @@ TEST(PasswordManager, test_save_get)
|
|||
const std::string key = "abc";
|
||||
|
||||
auto res2 = pwm.savePassword(key, password);
|
||||
ASSERT_THAT( res2.valid(), Eq(true) );
|
||||
ASSERT_TRUE(res2.valid());
|
||||
|
||||
std::string result;
|
||||
auto res3 = pwm.getPassword(key, result);
|
||||
ASSERT_THAT( res3.valid(), Eq(true) );
|
||||
ASSERT_THAT( res3.get(), Eq(true) );
|
||||
ASSERT_THAT( result, Eq(password) );
|
||||
|
||||
ASSERT_TRUE(res3.valid());
|
||||
ASSERT_TRUE(res3.get());
|
||||
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)
|
||||
{
|
||||
Expected<int> v = getAnswerToEverything();
|
||||
ASSERT_THAT(v.valid(), Eq(true));
|
||||
ASSERT_TRUE(v.valid());
|
||||
}
|
||||
|
||||
TEST(expected, get_when_valid_returns_value)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
|
|
@ -36,41 +44,48 @@ TEST(expected, T_fromException_get_thows)
|
|||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
auto e = Expected<int>::fromCode([]() -> int { return 42; });
|
||||
ASSERT_THAT(e.valid(), Eq(true));
|
||||
ASSERT_TRUE(e.valid());
|
||||
}
|
||||
|
||||
TEST(expected, T_fromCode_get)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
|
|
@ -82,21 +97,24 @@ TEST(expected, T_fromCode_E_get_thows)
|
|||
TEST(expected, T_fromCode_E_has_exception_true)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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<void> getNothing() { return Expected<void>(); }
|
||||
|
|
@ -105,7 +123,7 @@ Expected<void> getNothing() { return Expected<void>(); }
|
|||
TEST(expected_void, valid_when_valid_returns_true)
|
||||
{
|
||||
Expected<void> v = getNothing();
|
||||
ASSERT_THAT(v.valid(), Eq(true));
|
||||
ASSERT_TRUE(v.valid());
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
ASSERT_THAT(e.hasException<std::exception>(), Eq(true));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -9,7 +9,7 @@ TEST(ScopeGuard, normal_run_fun_on_destruction_1)
|
|||
{
|
||||
bool result = false;
|
||||
auto sg = scopeGuard([&result]() { result = true; });
|
||||
ASSERT_THAT(result, Eq(false));
|
||||
ASSERT_FALSE(result);
|
||||
}
|
||||
|
||||
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; });
|
||||
}
|
||||
|
||||
ASSERT_THAT(result, Eq(true));
|
||||
ASSERT_TRUE(result);
|
||||
}
|
||||
|
||||
TEST(ScopeGuard, dismiss)
|
||||
|
|
@ -30,7 +30,7 @@ TEST(ScopeGuard, dismiss)
|
|||
sg.dismiss();
|
||||
}
|
||||
|
||||
ASSERT_THAT(result, Eq(false));
|
||||
ASSERT_FALSE(result);
|
||||
}
|
||||
|
||||
TEST(ScopeGuard, SCOPE_EXIT_macro_1)
|
||||
|
|
@ -38,7 +38,7 @@ TEST(ScopeGuard, SCOPE_EXIT_macro_1)
|
|||
bool result = false;
|
||||
{
|
||||
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; };
|
||||
}
|
||||
|
||||
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 "ui_backupdialog.h"
|
||||
#include "BackupDialog.h"
|
||||
#include "ui_BackupDialog.h"
|
||||
|
||||
#include "BackupFormatModel.h"
|
||||
|
||||
|
|
@ -9,8 +9,6 @@
|
|||
#include <QScrollBar>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
BackupDialog::BackupDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::BackupDialog)
|
||||
|
|
@ -172,7 +170,8 @@ void BackupDialog::on_btnStart_clicked()
|
|||
{
|
||||
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;
|
||||
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.
|
||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||
m_config.writeToEnvironment(env);
|
||||
env.insert("SESSIONNAME", "Console");
|
||||
//env.insert("SESSIONNAME", "Console");
|
||||
auto p = new QProcess(this);
|
||||
ConnectTo(p);
|
||||
p->setProcessEnvironment(env);
|
||||
|
||||
#ifdef WIN32
|
||||
p->setCreateProcessArgumentsModifier([] (QProcess::CreateProcessArguments *args)
|
||||
{
|
||||
args->flags |= CREATE_NEW_CONSOLE;
|
||||
args->flags &= ~DETACHED_PROCESS;
|
||||
args->startupInfo->dwFlags &= ~STARTF_USESTDHANDLES;
|
||||
});
|
||||
#endif
|
||||
p->start(program, arguments);
|
||||
}
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
#include <QProcess>
|
||||
#include <QProcessEnvironment>
|
||||
#include "connectionconfig.h"
|
||||
#include "ConnectionConfig.h"
|
||||
|
||||
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 <QCoreApplication>
|
||||
#include <QProcessEnvironment>
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
#include "ConnectionList.h"
|
||||
#include "scopeguard.h"
|
||||
#include "ScopeGuard.h"
|
||||
#include "util.h"
|
||||
#include <QDir>
|
||||
#include <QStandardPaths>
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
#include "ConnectionListModel.h"
|
||||
#include "ConnectionList.h"
|
||||
#include "scopeguard.h"
|
||||
#include "ScopeGuard.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <botan/cryptobox.h>
|
||||
|
|
@ -6,8 +6,8 @@
|
|||
|
||||
#include <QAbstractListModel>
|
||||
|
||||
#include "connectionconfig.h"
|
||||
#include "expected.h"
|
||||
#include "ConnectionConfig.h"
|
||||
#include "Expected.h"
|
||||
|
||||
class ConnectionList;
|
||||
|
||||
|
|
@ -1,12 +1,11 @@
|
|||
#include "connectionmanagerwindow.h"
|
||||
#include "ui_connectionmanagerwindow.h"
|
||||
#include "ConnectionManagerWindow.h"
|
||||
#include "ui_ConnectionManagerWindow.h"
|
||||
//#include "mainwindow.h"
|
||||
#include "MasterController.h"
|
||||
#include <QDataWidgetMapper>
|
||||
#include <QMessageBox>
|
||||
#include <QStandardItemModel>
|
||||
|
||||
#include "connectionlistmodel.h"
|
||||
#include "ConnectionListModel.h"
|
||||
|
||||
ConnectionManagerWindow::ConnectionManagerWindow(MasterController *master, QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
|
|
@ -201,12 +201,12 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>23</height>
|
||||
<height>24</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
<property name="title">
|
||||
<string>File</string>
|
||||
<string>Fi&le</string>
|
||||
</property>
|
||||
<addaction name="actionQuit_application"/>
|
||||
</widget>
|
||||
|
|
@ -240,7 +240,7 @@
|
|||
<action name="actionAdd_Connection">
|
||||
<property name="icon">
|
||||
<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 name="text">
|
||||
<string>Add Connection</string>
|
||||
|
|
@ -248,9 +248,9 @@
|
|||
</action>
|
||||
<action name="actionDelete_connection">
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normalon>:/icons/server_delete.png</normalon>
|
||||
</iconset>
|
||||
<iconset resource="resources.qrc">
|
||||
<normaloff>:/icons/delete_connection.png</normaloff>
|
||||
<normalon>:/icons/delete_connection.png</normalon>:/icons/delete_connection.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Delete connection</string>
|
||||
|
|
@ -261,8 +261,9 @@
|
|||
</action>
|
||||
<action name="actionConnect">
|
||||
<property name="icon">
|
||||
<iconset resource="resources.qrc">
|
||||
<normaloff>:/icons/server_go.png</normaloff>:/icons/server_go.png</iconset>
|
||||
<iconset>
|
||||
<normalon>:/icons/open_query_window.png</normalon>
|
||||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Connect</string>
|
||||
|
|
@ -270,14 +271,14 @@
|
|||
</action>
|
||||
<action name="actionQuit_application">
|
||||
<property name="text">
|
||||
<string>Quit application</string>
|
||||
<string>&Quit application</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionBackup_database">
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normalon>:/icons/backups.png</normalon>
|
||||
</iconset>
|
||||
<iconset resource="resources.qrc">
|
||||
<normaloff>:/icons/backup_database.png</normaloff>
|
||||
<normalon>:/icons/backups.png</normalon>:/icons/backup_database.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Backup database</string>
|
||||
|
|
@ -286,7 +287,7 @@
|
|||
<action name="actionManage_server">
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normalon>:/icons/server_edit.png</normalon>
|
||||
<normalon>:/icons/manage_server.png</normalon>
|
||||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
#include "databaseinspectorwidget.h"
|
||||
#include "ui_databaseinspectorwidget.h"
|
||||
#include "DatabaseInspectorWidget.h"
|
||||
#include "ui_DatabaseInspectorWidget.h"
|
||||
|
||||
DatabaseInspectorWidget::DatabaseInspectorWidget(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
|
|
@ -1,28 +1,23 @@
|
|||
#include "databasewindow.h"
|
||||
#include "ui_databasewindow.h"
|
||||
#include "DatabaseWindow.h"
|
||||
#include "ui_DatabaseWindow.h"
|
||||
#include <QTimer>
|
||||
#include "GlobalIoService.h"
|
||||
|
||||
|
||||
DatabaseWindow::DatabaseWindow(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
ui(new Ui::DatabaseWindow)
|
||||
ui(new Ui::DatabaseWindow),
|
||||
m_dbConnection(*getGlobalAsioIoService())
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
m_dbConnection.setStateCallback([this](ASyncDBConnection::State st)
|
||||
{
|
||||
QueueTask([this, st]() { connectionStateChanged(st); });
|
||||
});
|
||||
|
||||
m_dbConnection.setNoticeCallback([this](Pgsql::ErrorDetails details)
|
||||
{
|
||||
QueueTask([this, details]() { receiveNotice(details); });
|
||||
});
|
||||
connect(&m_dbConnection, &ASyncDBConnection::onStateChanged, this, &DatabaseWindow::connectionStateChanged);
|
||||
connect(&m_dbConnection, &ASyncDBConnection::onNotice, this, &DatabaseWindow::receiveNotice);
|
||||
}
|
||||
|
||||
DatabaseWindow::~DatabaseWindow()
|
||||
{
|
||||
m_dbConnection.closeConnection();
|
||||
m_dbConnection.setStateCallback(nullptr);
|
||||
delete ui;
|
||||
}
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef DATABASEWINDOW_H
|
||||
#define DATABASEWINDOW_H
|
||||
|
||||
#include "asyncdbconnection.h"
|
||||
#include "ASyncDBConnection.h"
|
||||
#include "tsqueue.h"
|
||||
#include <QMainWindow>
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
#include "DatabasesTableModel.h"
|
||||
#include "PgsqlDatabaseCatalogue.h"
|
||||
#include "DatabasesTableModel.h"
|
||||
#include "PgDatabaseCatalogue.h"
|
||||
#include "PgDatabaseContainer.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();
|
||||
m_catalog = cat;
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
#ifndef DATABASESTABLEMODEL_H
|
||||
#ifndef DATABASESTABLEMODEL_H
|
||||
#define DATABASESTABLEMODEL_H
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
|
||||
class PgDatabaseContainer;
|
||||
class PgsqlDatabaseCatalogue;
|
||||
class PgDatabaseCatalogue;
|
||||
|
||||
/** Class for displaying the list of databases of a server in a QTableView
|
||||
*
|
||||
|
|
@ -22,7 +22,7 @@ public:
|
|||
|
||||
explicit DatabasesTableModel(QObject *parent);
|
||||
|
||||
void setDatabaseList(const PgsqlDatabaseCatalogue* cat);
|
||||
void setDatabaseList(const PgDatabaseCatalogue* cat);
|
||||
|
||||
// Header:
|
||||
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;
|
||||
|
||||
private:
|
||||
const PgsqlDatabaseCatalogue *m_catalog = nullptr;
|
||||
const PgDatabaseCatalogue *m_catalog = nullptr;
|
||||
const PgDatabaseContainer *m_databases = nullptr;
|
||||
};
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#include "explaintreemodelitem.h"
|
||||
#include "ExplainTreeModelItem.h"
|
||||
#include "json/json.h"
|
||||
#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 "ui_mainwindow.h"
|
||||
#include "ui_MainWindow.h"
|
||||
|
||||
#include <QStandardPaths>
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QTextTable>
|
||||
#include <QElapsedTimer>
|
||||
#include <windows.h>
|
||||
#include <algorithm>
|
||||
#include <QCloseEvent>
|
||||
#include <QMetaObject>
|
||||
#include <QMetaMethod>
|
||||
#include <querytab.h>
|
||||
#include "QueryTab.h"
|
||||
#include "util.h"
|
||||
#include "MasterController.h"
|
||||
#include "OpenDatabase.h"
|
||||
|
|
@ -132,6 +131,9 @@ void MainWindow::on_actionAbout_triggered()
|
|||
"\n"
|
||||
"Icons by fatcow http://www.fatcow.com/free-icons provided under Creative Commons "
|
||||
"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
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include "asyncdbconnection.h"
|
||||
#include "connectionconfig.h"
|
||||
#include "ASyncDBConnection.h"
|
||||
#include "ConnectionConfig.h"
|
||||
#include "tsqueue.h"
|
||||
#include <QLabel>
|
||||
#include "ASyncWindow.h"
|
||||
#include <QSocketNotifier>
|
||||
#include <memory>
|
||||
#include <future>
|
||||
#include "PgsqlConn.h"
|
||||
#include "Pgsql_Connection.h"
|
||||
#include <chrono>
|
||||
#include <deque>
|
||||
#include <mutex>
|
||||
|
|
@ -41,7 +41,7 @@ private:
|
|||
Ui::MainWindow *ui;
|
||||
|
||||
ConnectionConfig m_config;
|
||||
OpenDatabase *m_database;
|
||||
OpenDatabase *m_database = nullptr;
|
||||
|
||||
MasterController *m_masterController;
|
||||
|
||||
|
|
@ -45,12 +45,12 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>993</width>
|
||||
<height>22</height>
|
||||
<height>24</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuTest">
|
||||
<property name="title">
|
||||
<string>File</string>
|
||||
<string>Fi&le</string>
|
||||
</property>
|
||||
<addaction name="actionNew_SQL"/>
|
||||
<addaction name="actionLoad_SQL"/>
|
||||
|
|
@ -69,7 +69,7 @@
|
|||
</widget>
|
||||
<widget class="QMenu" name="menuQuery">
|
||||
<property name="title">
|
||||
<string>Query</string>
|
||||
<string>&Query</string>
|
||||
</property>
|
||||
<addaction name="actionExecute_SQL"/>
|
||||
<addaction name="actionExplain"/>
|
||||
|
|
@ -79,7 +79,7 @@
|
|||
</widget>
|
||||
<widget class="QMenu" name="menuView">
|
||||
<property name="title">
|
||||
<string>Window</string>
|
||||
<string>Wi&ndow</string>
|
||||
</property>
|
||||
<addaction name="actionShow_connection_manager"/>
|
||||
</widget>
|
||||
|
|
@ -126,7 +126,7 @@
|
|||
<normaloff>:/icons/folder.png</normaloff>:/icons/folder.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Load SQL</string>
|
||||
<string>&Load SQL</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+O</string>
|
||||
|
|
@ -138,7 +138,7 @@
|
|||
<normaloff>:/icons/script_save.png</normaloff>:/icons/script_save.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Save SQL</string>
|
||||
<string>&Save SQL</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+S</string>
|
||||
|
|
@ -150,7 +150,7 @@
|
|||
<normaloff>:/icons/table_save.png</normaloff>:/icons/table_save.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Export data</string>
|
||||
<string>&Export data</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionClose">
|
||||
|
|
@ -160,7 +160,7 @@
|
|||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Close</string>
|
||||
<string>&Close</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+F4</string>
|
||||
|
|
@ -168,12 +168,12 @@
|
|||
</action>
|
||||
<action name="actionAbout">
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normalon>:/icons/information.png</normalon>
|
||||
</iconset>
|
||||
<iconset resource="resources.qrc">
|
||||
<normaloff>:/icons/about.png</normaloff>
|
||||
<normalon>:/icons/information.png</normalon>:/icons/about.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>About</string>
|
||||
<string>&About</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionExecute_SQL">
|
||||
|
|
@ -183,7 +183,7 @@
|
|||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Execute queries</string>
|
||||
<string>&Execute queries</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Execute the (selected) queries</string>
|
||||
|
|
@ -199,7 +199,7 @@
|
|||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Cancel</string>
|
||||
<string>&Cancel</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Alt+Pause</string>
|
||||
|
|
@ -211,7 +211,7 @@
|
|||
<normaloff>:/icons/lightbulb.png</normaloff>:/icons/lightbulb.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Explain Analyze</string>
|
||||
<string>Ex&plain Analyze</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Shift+F7</string>
|
||||
|
|
@ -219,22 +219,22 @@
|
|||
</action>
|
||||
<action name="actionSave_SQL_as">
|
||||
<property name="text">
|
||||
<string>Save SQL as</string>
|
||||
<string>Sa&ve SQL as</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSave_copy_of_SQL_as">
|
||||
<property name="text">
|
||||
<string>Save copy of SQL as</string>
|
||||
<string>Save copy &of SQL as</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionNew_SQL">
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normalon>:/icons/page_white_add.png</normalon>
|
||||
</iconset>
|
||||
<iconset resource="resources.qrc">
|
||||
<normaloff>:/icons/new_query_tab.png</normaloff>
|
||||
<normalon>:/icons/page_white_add.png</normalon>:/icons/new_query_tab.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>New SQL</string>
|
||||
<string>&New SQL</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+N</string>
|
||||
|
|
@ -247,7 +247,7 @@
|
|||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Explain</string>
|
||||
<string>E&xplain</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Explain the (selected) query</string>
|
||||
|
|
@ -258,7 +258,7 @@
|
|||
</action>
|
||||
<action name="actionShow_connection_manager">
|
||||
<property name="text">
|
||||
<string>Show connection manager</string>
|
||||
<string>&Show connection manager</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionCopy">
|
||||
|
|
@ -268,7 +268,7 @@
|
|||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Copy</string>
|
||||
<string>&Copy</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+C</string>
|
||||
|
|
@ -281,7 +281,7 @@
|
|||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Copy as C-string</string>
|
||||
<string>Copy as C-&string</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Alt+C</string>
|
||||
|
|
@ -2,8 +2,10 @@
|
|||
#define MASTERCONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <future>
|
||||
#include <map>
|
||||
|
||||
|
||||
class ConnectionConfig;
|
||||
class ConnectionList;
|
||||
class ConnectionListModel;
|
||||
|
|
@ -39,6 +41,7 @@ private:
|
|||
ConnectionList *m_connectionList = nullptr;
|
||||
ConnectionListModel *m_connectionListModel = nullptr;
|
||||
ConnectionManagerWindow *m_connectionManagerWindow = nullptr;
|
||||
|
||||
};
|
||||
|
||||
#endif // MASTERCONTROLLER_H
|
||||
|
|
@ -1,23 +1,25 @@
|
|||
#include "OpenDatabase.h"
|
||||
#include "pgsqldatabasecatalogue.h"
|
||||
#include "PgsqlConn.h"
|
||||
#include "typeselectionitemmodel.h"
|
||||
#include "OpenDatabase.h"
|
||||
#include "PgDatabaseCatalogue.h"
|
||||
#include "Pgsql_Connection.h"
|
||||
#include "TypeSelectionItemModel.h"
|
||||
|
||||
Expected<OpenDatabase*> OpenDatabase::createOpenDatabase(const ConnectionConfig &cfg)
|
||||
{
|
||||
OpenDatabase *odb = new OpenDatabase(cfg, nullptr);
|
||||
if (odb->Init()) {
|
||||
|
||||
return odb;
|
||||
|
||||
}
|
||||
return odb;
|
||||
//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)
|
||||
: QObject(parent)
|
||||
, m_config(cfg)
|
||||
, m_catalogue(new PgsqlDatabaseCatalogue)
|
||||
, m_catalogue(new PgDatabaseCatalogue)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -33,11 +35,12 @@ bool OpenDatabase::Init()
|
|||
auto vals = m_config.getValues();
|
||||
if (conn.connect(kw, vals, 0)) {
|
||||
m_catalogue->loadAll(conn);
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
PgsqlDatabaseCatalogue* OpenDatabase::catalogue()
|
||||
PgDatabaseCatalogue* OpenDatabase::catalogue()
|
||||
{
|
||||
return m_catalogue;
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
#ifndef OPENDATABASE_H
|
||||
#ifndef OPENDATABASE_H
|
||||
#define OPENDATABASE_H
|
||||
|
||||
#include <QObject>
|
||||
#include "connectionconfig.h"
|
||||
#include "expected.h"
|
||||
#include "ConnectionConfig.h"
|
||||
#include "Expected.h"
|
||||
|
||||
class PgsqlDatabaseCatalogue;
|
||||
class PgDatabaseCatalogue;
|
||||
class TypeSelectionItemModel;
|
||||
|
||||
/** Instances of this class represent a single database on which atleast one
|
||||
|
|
@ -21,7 +21,7 @@ public:
|
|||
OpenDatabase& operator=(const OpenDatabase &) = delete;
|
||||
~OpenDatabase();
|
||||
|
||||
PgsqlDatabaseCatalogue* catalogue();
|
||||
PgDatabaseCatalogue* catalogue();
|
||||
TypeSelectionItemModel* typeSelectionModel();
|
||||
signals:
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ public slots:
|
|||
|
||||
private:
|
||||
ConnectionConfig m_config;
|
||||
PgsqlDatabaseCatalogue *m_catalogue;
|
||||
PgDatabaseCatalogue *m_catalogue;
|
||||
|
||||
TypeSelectionItemModel *m_typeSelectionModel = nullptr;
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#ifndef PARAMLISTMODEL_H
|
||||
#ifndef PARAMLISTMODEL_H
|
||||
#define PARAMLISTMODEL_H
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
|
|
@ -11,7 +11,7 @@ public:
|
|||
class Param {
|
||||
public:
|
||||
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(const QString &v, const QString t)
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef PGAUTHID_H
|
||||
#define PGAUTHID_H
|
||||
|
||||
#include <pgsql/libpq-fe.h>
|
||||
#include <libpq-fe.h>
|
||||
#include <QString>
|
||||
#include <QDateTime>
|
||||
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
#include "PgAuthIdContainer.h"
|
||||
#include "PgsqlConn.h"
|
||||
#include "PgsqlDatabaseCatalogue.h"
|
||||
#include "PgAuthIdContainer.h"
|
||||
#include "Pgsql_Connection.h"
|
||||
#include "PgDatabaseCatalogue.h"
|
||||
|
||||
PgAuthIdContainer::PgAuthIdContainer(PgsqlDatabaseCatalogue *cat)
|
||||
PgAuthIdContainer::PgAuthIdContainer(PgDatabaseCatalogue *cat)
|
||||
: PgContainer<PgAuthId>(cat)
|
||||
{}
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#ifndef PGAUTHIDCONTAINER_H
|
||||
#ifndef PGAUTHIDCONTAINER_H
|
||||
#define PGAUTHIDCONTAINER_H
|
||||
|
||||
#include <vector>
|
||||
|
|
@ -14,7 +14,7 @@ namespace Pgsql {
|
|||
|
||||
class PgAuthIdContainer: public PgContainer<PgAuthId> {
|
||||
public:
|
||||
explicit PgAuthIdContainer(PgsqlDatabaseCatalogue *cat);
|
||||
explicit PgAuthIdContainer(PgDatabaseCatalogue *cat);
|
||||
|
||||
std::string getLoadQuery() const;
|
||||
void load(const Pgsql::Result &res);
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
#include "pgclass.h"
|
||||
#include "PgClass.h"
|
||||
|
||||
PgClass::PgClass() = default;
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
#define PGCLASS_H
|
||||
|
||||
#include <QString>
|
||||
#include <pgsql/libpq-fe.h>
|
||||
#include <libpq-fe.h>
|
||||
|
||||
class PgClass {
|
||||
public:
|
||||
|
|
@ -1,18 +1,18 @@
|
|||
#ifndef PGCONTAINER_H
|
||||
#ifndef PGCONTAINER_H
|
||||
#define PGCONTAINER_H
|
||||
|
||||
#include <QString>
|
||||
#include <vector>
|
||||
#include <pgsql/libpq-fe.h>
|
||||
#include <libpq-fe.h>
|
||||
|
||||
class PgsqlDatabaseCatalogue;
|
||||
class PgDatabaseCatalogue;
|
||||
|
||||
template<typename T>
|
||||
class PgContainer {
|
||||
public:
|
||||
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)
|
||||
{}
|
||||
|
||||
|
|
@ -60,7 +60,7 @@ public:
|
|||
return m_container.at(idx);
|
||||
}
|
||||
protected:
|
||||
PgsqlDatabaseCatalogue *m_catalogue;
|
||||
PgDatabaseCatalogue *m_catalogue;
|
||||
t_Container m_container;
|
||||
private:
|
||||
T m_invalidInstance;
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
#define PGDATABASE_H
|
||||
|
||||
#include <QString>
|
||||
#include <pgsql/libpq-fe.h>
|
||||
#include <libpq-fe.h>
|
||||
|
||||
class PgDatabase {
|
||||
public:
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
#include "PgsqlDatabaseCatalogue.h"
|
||||
#include "PgDatabaseCatalogue.h"
|
||||
#include "PgTypeContainer.h"
|
||||
#include "PgDatabaseContainer.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;
|
||||
const PgAuthIdContainer *auth_ids = cat->authIds();
|
||||
|
|
@ -18,23 +18,23 @@ QString getRoleNameFromOid(const PgsqlDatabaseCatalogue *cat, Oid oid)
|
|||
return name;
|
||||
}
|
||||
|
||||
PgsqlDatabaseCatalogue::PgsqlDatabaseCatalogue()
|
||||
PgDatabaseCatalogue::PgDatabaseCatalogue()
|
||||
{
|
||||
}
|
||||
|
||||
PgsqlDatabaseCatalogue::~PgsqlDatabaseCatalogue()
|
||||
PgDatabaseCatalogue::~PgDatabaseCatalogue()
|
||||
{
|
||||
delete m_types;
|
||||
}
|
||||
|
||||
void PgsqlDatabaseCatalogue::loadAll(Pgsql::Connection &conn)
|
||||
void PgDatabaseCatalogue::loadAll(Pgsql::Connection &conn)
|
||||
{
|
||||
loadTypes(conn);
|
||||
loadDatabases(conn);
|
||||
loadAuthIds(conn);
|
||||
}
|
||||
|
||||
void PgsqlDatabaseCatalogue::loadInfo(Pgsql::Connection &conn)
|
||||
void PgDatabaseCatalogue::loadInfo(Pgsql::Connection &conn)
|
||||
{
|
||||
Pgsql::Result r = conn.query("SHOW server_version_num");
|
||||
if (r && r.resultStatus() == PGRES_TUPLES_OK)
|
||||
|
|
@ -47,7 +47,7 @@ void PgsqlDatabaseCatalogue::loadInfo(Pgsql::Connection &conn)
|
|||
m_serverVersionString = r.get(0, 0).asQString();
|
||||
}
|
||||
|
||||
void PgsqlDatabaseCatalogue::loadTypes(Pgsql::Connection &conn)
|
||||
void PgDatabaseCatalogue::loadTypes(Pgsql::Connection &conn)
|
||||
{
|
||||
if (m_types == nullptr)
|
||||
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)
|
||||
m_databases = new PgDatabaseContainer(this);
|
||||
|
|
@ -75,7 +75,7 @@ void PgsqlDatabaseCatalogue::loadDatabases(Pgsql::Connection &conn)
|
|||
throw std::runtime_error("Query failed");
|
||||
}
|
||||
|
||||
void PgsqlDatabaseCatalogue::loadAuthIds(Pgsql::Connection &conn)
|
||||
void PgDatabaseCatalogue::loadAuthIds(Pgsql::Connection &conn)
|
||||
{
|
||||
if (m_authIds == nullptr)
|
||||
m_authIds = new PgAuthIdContainer(this);
|
||||
|
|
@ -88,27 +88,27 @@ void PgsqlDatabaseCatalogue::loadAuthIds(Pgsql::Connection &conn)
|
|||
throw std::runtime_error("Query failed");
|
||||
}
|
||||
|
||||
const QString& PgsqlDatabaseCatalogue::serverVersionString() const
|
||||
const QString& PgDatabaseCatalogue::serverVersionString() const
|
||||
{
|
||||
return m_serverVersionString;
|
||||
}
|
||||
|
||||
int PgsqlDatabaseCatalogue::serverVersion() const
|
||||
int PgDatabaseCatalogue::serverVersion() const
|
||||
{
|
||||
return m_serverVersion;
|
||||
}
|
||||
|
||||
const PgTypeContainer* PgsqlDatabaseCatalogue::types() const
|
||||
const PgTypeContainer* PgDatabaseCatalogue::types() const
|
||||
{
|
||||
return m_types;
|
||||
}
|
||||
|
||||
const PgDatabaseContainer *PgsqlDatabaseCatalogue::databases() const
|
||||
const PgDatabaseContainer *PgDatabaseCatalogue::databases() const
|
||||
{
|
||||
return m_databases;
|
||||
}
|
||||
|
||||
const PgAuthIdContainer *PgsqlDatabaseCatalogue::authIds() const
|
||||
const PgAuthIdContainer *PgDatabaseCatalogue::authIds() const
|
||||
{
|
||||
return m_authIds;
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef PGSQLDATABASECATALOGUE_H
|
||||
#define PGSQLDATABASECATALOGUE_H
|
||||
|
||||
#include <pgsql/libpq-fe.h>
|
||||
#include <libpq-fe.h>
|
||||
#include <QString>
|
||||
#include <vector>
|
||||
|
||||
|
|
@ -15,13 +15,13 @@ class PgTypeContainer;
|
|||
class PgDatabaseContainer;
|
||||
class PgAuthIdContainer;
|
||||
|
||||
class PgsqlDatabaseCatalogue {
|
||||
class PgDatabaseCatalogue {
|
||||
public:
|
||||
PgsqlDatabaseCatalogue();
|
||||
PgsqlDatabaseCatalogue(const PgsqlDatabaseCatalogue&) = delete;
|
||||
PgsqlDatabaseCatalogue& operator = (const PgsqlDatabaseCatalogue&) = delete;
|
||||
PgDatabaseCatalogue();
|
||||
PgDatabaseCatalogue(const PgDatabaseCatalogue&) = delete;
|
||||
PgDatabaseCatalogue& operator = (const PgDatabaseCatalogue&) = delete;
|
||||
|
||||
~PgsqlDatabaseCatalogue();
|
||||
~PgDatabaseCatalogue();
|
||||
|
||||
|
||||
void loadAll(Pgsql::Connection &conn);
|
||||
|
|
@ -44,6 +44,6 @@ private:
|
|||
PgAuthIdContainer *m_authIds = nullptr;
|
||||
};
|
||||
|
||||
QString getRoleNameFromOid(const PgsqlDatabaseCatalogue *cat, Oid oid);
|
||||
QString getRoleNameFromOid(const PgDatabaseCatalogue *cat, Oid oid);
|
||||
|
||||
#endif // PGSQLDATABASECATALOGUE_H
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
#include "PgDatabaseContainer.h"
|
||||
#include "PgsqlConn.h"
|
||||
#include "PgDatabaseContainer.h"
|
||||
#include "Pgsql_Connection.h"
|
||||
|
||||
PgDatabaseContainer::PgDatabaseContainer(PgsqlDatabaseCatalogue *cat)
|
||||
PgDatabaseContainer::PgDatabaseContainer(PgDatabaseCatalogue *cat)
|
||||
: PgContainer<PgDatabase>(cat)
|
||||
{}
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#ifndef PGDATABASECONTAINER_H
|
||||
#ifndef PGDATABASECONTAINER_H
|
||||
#define PGDATABASECONTAINER_H
|
||||
|
||||
#include <vector>
|
||||
|
|
@ -14,7 +14,7 @@ namespace Pgsql {
|
|||
|
||||
class PgDatabaseContainer: public PgContainer<PgDatabase> {
|
||||
public:
|
||||
explicit PgDatabaseContainer(PgsqlDatabaseCatalogue *cat);
|
||||
explicit PgDatabaseContainer(PgDatabaseCatalogue *cat);
|
||||
|
||||
std::string getLoadQuery() const;
|
||||
void load(const Pgsql::Result &res);
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#include "pgnamespace.h"
|
||||
#include "PgNamespace.h"
|
||||
|
||||
PgNamespace::PgNamespace() = default;
|
||||
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
#define PGNAMESPACE_H
|
||||
|
||||
#include <QString>
|
||||
#include <pgsql/libpq-fe.h>
|
||||
#include <libpq-fe.h>
|
||||
|
||||
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
|
||||
|
||||
#include <QString>
|
||||
#include <pgsql/libpq-fe.h>
|
||||
#include <libpq-fe.h>
|
||||
|
||||
class PgType {
|
||||
public:
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
#include "pgtypecontainer.h"
|
||||
#include "PgsqlConn.h"
|
||||
#include "PgTypeContainer.h"
|
||||
#include "Pgsql_Connection.h"
|
||||
#include <algorithm>
|
||||
|
||||
PgTypeContainer::PgTypeContainer(PgsqlDatabaseCatalogue *cat)
|
||||
PgTypeContainer::PgTypeContainer(PgDatabaseCatalogue *cat)
|
||||
: PgContainer<PgType>(cat)
|
||||
{}
|
||||
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
#ifndef PGTYPECONTAINER_H
|
||||
#ifndef PGTYPECONTAINER_H
|
||||
#define PGTYPECONTAINER_H
|
||||
|
||||
#include <vector>
|
||||
#include "pgtype.h"
|
||||
#include "PgType.h"
|
||||
#include "PgContainer.h"
|
||||
|
||||
namespace Pgsql {
|
||||
|
|
@ -15,7 +15,7 @@ class PgTypeContainer: public PgContainer<PgType> {
|
|||
public:
|
||||
// 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 end() const { return m_types.end(); }
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
#include "queryexplainmodel.h"
|
||||
#include "QueryExplainModel.h"
|
||||
#include <QColor>
|
||||
#include <QSize>
|
||||
#include <cmath>
|
||||
|
||||
const int c_ColumnNode = 0;
|
||||
const int c_ColumnExclusive = 1;
|
||||
|
|
@ -79,7 +80,7 @@ if (role == Qt::DisplayRole) {
|
|||
}
|
||||
}
|
||||
if (col == c_ColumnEstErr) {
|
||||
float e = fabs(item->estimateError());
|
||||
float e = std::fabs(item->estimateError());
|
||||
if (e > 1000.0f) {
|
||||
result = QColor(255, 192, 192);
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include <QAbstractItemModel>
|
||||
#include <string>
|
||||
#include "explaintreemodelitem.h"
|
||||
#include "ExplainTreeModelItem.h"
|
||||
|
||||
/** \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 <QBrush>
|
||||
#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