Merge branch 'port-to-linux'

This commit is contained in:
Eelke Klein 2017-09-10 10:15:14 +02:00
commit 976623ca9b
180 changed files with 1150 additions and 1415 deletions

5
.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
*.swp
build/*
*.kdev4
.kdev4/*

18
BUILD Normal file
View 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

View file

@ -1,6 +0,0 @@
#include "Core.h"
Core::Core()
{
}

View file

@ -1,12 +0,0 @@
#ifndef CORE_H
#define CORE_H
class Core
{
public:
Core();
};
#endif // CORE_H

View file

@ -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
}

View file

@ -1,10 +0,0 @@
TEMPLATE = subdirs
DEFINES += BOOST_ENABLE_ASSERT_HANDLER
SUBDIRS += src \
core
CONFIG(debug, debug|release) {
SUBDIRS += tests
}

View file

@ -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);
}
}

View file

@ -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
View 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)

View file

@ -1,5 +0,0 @@
#include "pgtype.h"
#include "PgsqlConn.h"
PgType::PgType() = default;

View 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
View 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)

View file

@ -1,4 +1,4 @@
#include "csvwriter.h"
#include "CsvWriter.h"
CsvWriter::CsvWriter()
{}

View file

@ -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);

View file

@ -13,7 +13,6 @@
#include <boost/assert.hpp>
#include "Core.h"
using namespace Botan;

View file

@ -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)
{
@ -116,6 +117,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

View file

@ -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
View file

@ -0,0 +1,8 @@
#include <gtest/gtest.h>
int main(int argc, char *argv[])
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View file

@ -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);
}

View file

@ -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)
@ -37,11 +37,11 @@ TEST(PasswordManager, unlock_fails)
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());
ASSERT_THAT( res2.get(), Eq(false) );
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);
}

View 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);
}

View file

@ -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));
}

View file

@ -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

View 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);
}

View 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

View file

@ -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);
}

View file

@ -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
View 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
)

View file

@ -1,4 +1,4 @@
#include "connectionconfig.h"
#include "ConnectionConfig.h"
#include "util.h"
#include <QCoreApplication>
#include <QProcessEnvironment>

View file

@ -1,5 +1,5 @@
#include "ConnectionList.h"
#include "scopeguard.h"
#include "ScopeGuard.h"
#include "util.h"
#include <QDir>
#include <QStandardPaths>

View file

@ -1,6 +1,6 @@
#include "ConnectionListModel.h"
#include "ConnectionList.h"
#include "scopeguard.h"
#include "ScopeGuard.h"
#include "util.h"
#include <botan/cryptobox.h>

View file

@ -6,8 +6,8 @@
#include <QAbstractListModel>
#include "connectionconfig.h"
#include "expected.h"
#include "ConnectionConfig.h"
#include "Expected.h"
class ConnectionList;

View file

@ -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)

View file

@ -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&amp;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>&amp;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">

View file

@ -1,5 +1,5 @@
#include "databaseinspectorwidget.h"
#include "ui_databaseinspectorwidget.h"
#include "DatabaseInspectorWidget.h"
#include "ui_DatabaseInspectorWidget.h"
DatabaseInspectorWidget::DatabaseInspectorWidget(QWidget *parent) :
QWidget(parent),

View file

@ -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;
}

View file

@ -1,7 +1,7 @@
#ifndef DATABASEWINDOW_H
#define DATABASEWINDOW_H
#include "asyncdbconnection.h"
#include "ASyncDBConnection.h"
#include "tsqueue.h"
#include <QMainWindow>

View file

@ -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;

View file

@ -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;
};

View file

@ -1,4 +1,4 @@
#include "explaintreemodelitem.h"
#include "ExplainTreeModelItem.h"
#include "json/json.h"
#include <limits>

View 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;
}

View file

@ -0,0 +1,6 @@
#pragma once
#include <memory>
#include <boost/asio.hpp>
std::shared_ptr<boost::asio::io_service> getGlobalAsioIoService();

View file

@ -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."
));
}

View file

@ -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;

View file

@ -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&amp;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>&amp;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&amp;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>&amp;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>&amp;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>&amp;Export data</string>
</property>
</action>
<action name="actionClose">
@ -160,7 +160,7 @@
</iconset>
</property>
<property name="text">
<string>Close</string>
<string>&amp;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>&amp;About</string>
</property>
</action>
<action name="actionExecute_SQL">
@ -183,7 +183,7 @@
</iconset>
</property>
<property name="text">
<string>Execute queries</string>
<string>&amp;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>&amp;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&amp;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&amp;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 &amp;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>&amp;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&amp;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>&amp;Show connection manager</string>
</property>
</action>
<action name="actionCopy">
@ -268,7 +268,7 @@
</iconset>
</property>
<property name="text">
<string>Copy</string>
<string>&amp;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-&amp;string</string>
</property>
<property name="shortcut">
<string>Ctrl+Alt+C</string>

View file

@ -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

View file

@ -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 false;
}
PgsqlDatabaseCatalogue* OpenDatabase::catalogue()
PgDatabaseCatalogue* OpenDatabase::catalogue()
{
return m_catalogue;
}

View file

@ -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;

View file

@ -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)

View file

@ -1,7 +1,7 @@
#ifndef PGAUTHID_H
#define PGAUTHID_H
#include <pgsql/libpq-fe.h>
#include <libpq-fe.h>
#include <QString>
#include <QDateTime>

View file

@ -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)
{}

View file

@ -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);

View file

@ -1,3 +1,3 @@
#include "pgclass.h"
#include "PgClass.h"
PgClass::PgClass() = default;

View file

@ -2,7 +2,7 @@
#define PGCLASS_H
#include <QString>
#include <pgsql/libpq-fe.h>
#include <libpq-fe.h>
class PgClass {
public:

View file

@ -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;

View file

@ -2,7 +2,7 @@
#define PGDATABASE_H
#include <QString>
#include <pgsql/libpq-fe.h>
#include <libpq-fe.h>
class PgDatabase {
public:

View file

@ -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;
}

View file

@ -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

View file

@ -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)
{}

View file

@ -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);

View file

@ -1,4 +1,4 @@
#include "pgnamespace.h"
#include "PgNamespace.h"
PgNamespace::PgNamespace() = default;

View file

@ -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
View file

@ -0,0 +1,5 @@
#include "PgType.h"
#include "Pgsql_Connection.h"
PgType::PgType() = default;

View file

@ -2,7 +2,7 @@
#define PGTYPE_H
#include <QString>
#include <pgsql/libpq-fe.h>
#include <libpq-fe.h>
class PgType {
public:

View file

@ -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)
{}

View file

@ -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(); }

View file

@ -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);
}

View file

@ -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.
*/

View file

@ -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