diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e293239 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.swp +build/* +*.kdev4 +.kdev4/* + diff --git a/BUILD b/BUILD new file mode 100644 index 0000000..3f4f16a --- /dev/null +++ b/BUILD @@ -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 diff --git a/core/Core.cpp b/core/Core.cpp deleted file mode 100644 index dd60b7d..0000000 --- a/core/Core.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "Core.h" - - -Core::Core() -{ -} diff --git a/core/Core.h b/core/Core.h deleted file mode 100644 index 6ecb6d3..0000000 --- a/core/Core.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef CORE_H -#define CORE_H - - -class Core -{ - -public: - Core(); -}; - -#endif // CORE_H diff --git a/core/core.pro b/core/core.pro deleted file mode 100644 index 52efebe..0000000 --- a/core/core.pro +++ /dev/null @@ -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 -} diff --git a/pglabAll.pro b/pglabAll.pro deleted file mode 100644 index 14311a6..0000000 --- a/pglabAll.pro +++ /dev/null @@ -1,10 +0,0 @@ -TEMPLATE = subdirs - -DEFINES += BOOST_ENABLE_ASSERT_HANDLER - -SUBDIRS += src \ - core - -CONFIG(debug, debug|release) { - SUBDIRS += tests -} diff --git a/src/ASyncDBConnection.cpp b/src/ASyncDBConnection.cpp deleted file mode 100644 index 95fa5f5..0000000 --- a/src/ASyncDBConnection.cpp +++ /dev/null @@ -1,352 +0,0 @@ -#include "asyncdbconnection.h" -#include "waithandlelist.h" -#include "scopeguard.h" -#include - -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 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 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 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 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 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 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 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 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 lg(m_noticeCallback.m_mutex); - if (m_noticeCallback.m_func) { - Pgsql::ErrorDetails details = Pgsql::ErrorDetails::createErrorDetailsFromPGresult(result); - m_noticeCallback.m_func(details); - } -} diff --git a/src/ASyncDBConnection.h b/src/ASyncDBConnection.h deleted file mode 100644 index 07bb1bf..0000000 --- a/src/ASyncDBConnection.h +++ /dev/null @@ -1,137 +0,0 @@ -#ifndef ASYNCDBCONNECTION_H -#define ASYNCDBCONNECTION_H - -#include "PgsqlConn.h" -#include "Pgsql_Params.h" -#include "win32event.h" -#include "connectionconfig.h" -#include -#include -#include -#include -#include -#include - -/** \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, qint64)>; - using on_state_callback = std::function; - using on_notice_callback = std::function; - - 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; - 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 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..7bff55f --- /dev/null +++ b/src/CMakeLists.txt @@ -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) + + + diff --git a/src/PgType.cpp b/src/PgType.cpp deleted file mode 100644 index 71939b7..0000000 --- a/src/PgType.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "pgtype.h" -#include "PgsqlConn.h" - -PgType::PgType() = default; - diff --git a/src/cmake/Modules/FindBotan.cmake b/src/cmake/Modules/FindBotan.cmake new file mode 100644 index 0000000..1feb01b --- /dev/null +++ b/src/cmake/Modules/FindBotan.cmake @@ -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() diff --git a/core/BackupFormatModel.cpp b/src/core/BackupFormatModel.cpp similarity index 100% rename from core/BackupFormatModel.cpp rename to src/core/BackupFormatModel.cpp diff --git a/core/BackupFormatModel.h b/src/core/BackupFormatModel.h similarity index 100% rename from core/BackupFormatModel.h rename to src/core/BackupFormatModel.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt new file mode 100644 index 0000000..95b09fc --- /dev/null +++ b/src/core/CMakeLists.txt @@ -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 + $ +) + +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) diff --git a/core/CsvWriter.cpp b/src/core/CsvWriter.cpp similarity index 97% rename from core/CsvWriter.cpp rename to src/core/CsvWriter.cpp index a2bb973..b51ace3 100644 --- a/core/CsvWriter.cpp +++ b/src/core/CsvWriter.cpp @@ -1,4 +1,4 @@ -#include "csvwriter.h" +#include "CsvWriter.h" CsvWriter::CsvWriter() {} diff --git a/core/CsvWriter.h b/src/core/CsvWriter.h similarity index 100% rename from core/CsvWriter.h rename to src/core/CsvWriter.h diff --git a/core/Expected.h b/src/core/Expected.h similarity index 99% rename from core/Expected.h rename to src/core/Expected.h index 8813272..8d78941 100644 --- a/core/Expected.h +++ b/src/core/Expected.h @@ -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); diff --git a/core/PasswordManager.cpp b/src/core/PasswordManager.cpp similarity index 99% rename from core/PasswordManager.cpp rename to src/core/PasswordManager.cpp index 597e7c9..60ca821 100644 --- a/core/PasswordManager.cpp +++ b/src/core/PasswordManager.cpp @@ -13,7 +13,6 @@ #include -#include "Core.h" using namespace Botan; diff --git a/core/PasswordManager.h b/src/core/PasswordManager.h similarity index 100% rename from core/PasswordManager.h rename to src/core/PasswordManager.h diff --git a/core/ScopeGuard.h b/src/core/ScopeGuard.h similarity index 100% rename from core/ScopeGuard.h rename to src/core/ScopeGuard.h diff --git a/core/SqlLexer.cpp b/src/core/SqlLexer.cpp similarity index 68% rename from core/SqlLexer.cpp rename to src/core/SqlLexer.cpp index bbc8deb..f28eedb 100644 --- a/core/SqlLexer.cpp +++ b/src/core/SqlLexer.cpp @@ -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 (;;) { diff --git a/core/SqlLexer.h b/src/core/SqlLexer.h similarity index 88% rename from core/SqlLexer.h rename to src/core/SqlLexer.h index c3e51f8..2ad3405 100644 --- a/core/SqlLexer.h +++ b/src/core/SqlLexer.h @@ -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 { diff --git a/core/my_boost_assert_handler.cpp b/src/core/my_boost_assert_handler.cpp similarity index 100% rename from core/my_boost_assert_handler.cpp rename to src/core/my_boost_assert_handler.cpp diff --git a/src/core/test/main.cpp b/src/core/test/main.cpp new file mode 100644 index 0000000..65b7839 --- /dev/null +++ b/src/core/test/main.cpp @@ -0,0 +1,8 @@ +#include + +int main(int argc, char *argv[]) +{ + ::testing::InitGoogleTest(&argc, argv); + + return RUN_ALL_TESTS(); +} diff --git a/tests/auto/mycase/tst_CsvWriter.h b/src/core/test/tst_CsvWriter.cpp similarity index 89% rename from tests/auto/mycase/tst_CsvWriter.h rename to src/core/test/tst_CsvWriter.cpp index ac48b9d..faac727 100644 --- a/tests/auto/mycase/tst_CsvWriter.h +++ b/src/core/test/tst_CsvWriter.cpp @@ -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); } diff --git a/tests/auto/mycase/tst_PasswordManager.h b/src/core/test/tst_PasswordManager.cpp similarity index 74% rename from tests/auto/mycase/tst_PasswordManager.h rename to src/core/test/tst_PasswordManager.cpp index a3da28b..bbcf591 100644 --- a/tests/auto/mycase/tst_PasswordManager.h +++ b/src/core/test/tst_PasswordManager.cpp @@ -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); } diff --git a/src/core/test/tst_SqlLexer.cpp b/src/core/test/tst_SqlLexer.cpp new file mode 100644 index 0000000..a8232b6 --- /dev/null +++ b/src/core/test/tst_SqlLexer.cpp @@ -0,0 +1,38 @@ +#include +#include +#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); +} + diff --git a/tests/auto/mycase/tst_expected.h b/src/core/test/tst_expected.cpp similarity index 80% rename from tests/auto/mycase/tst_expected.h rename to src/core/test/tst_expected.cpp index 8632ff8..babda3b 100644 --- a/tests/auto/mycase/tst_expected.h +++ b/src/core/test/tst_expected.cpp @@ -9,25 +9,33 @@ Expected getAnswerToEverything() { return 42; } TEST(expected, valid_when_valid_returns_true) { Expected v = getAnswerToEverything(); - ASSERT_THAT(v.valid(), Eq(true)); + ASSERT_TRUE(v.valid()); } TEST(expected, get_when_valid_returns_value) { Expected v = getAnswerToEverything(); - ASSERT_THAT(v.get(), Eq(42)); + ASSERT_EQ(v.get(), 42); +} + +TEST(expected, get_when_valid_returns_value_copycon) +{ + Expected t = getAnswerToEverything(); + Expected v(t); + ASSERT_TRUE(v.valid()); + ASSERT_EQ(v.get(), 42); } TEST(expected, hasException_when_valid_returns_false) { Expected v = getAnswerToEverything(); - ASSERT_THAT(v.hasException(), Eq(false)); + ASSERT_FALSE(v.hasException()); } TEST(expected, T_fromException_is_not_valid) { auto e = Expected::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::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::fromException(std::runtime_error("hello")); - ASSERT_THAT(e.hasException(), Eq(true)); + ASSERT_TRUE(e.hasException()); } TEST(expected, T_fromException_has_exception_false) { auto e = Expected::fromException(std::runtime_error("hello")); - ASSERT_THAT(e.hasException(), Eq(false)); + ASSERT_FALSE(e.hasException()); } TEST(expected, T_fromException_has_derived_exception) { auto e = Expected::fromException(std::runtime_error("hello")); - ASSERT_THAT(e.hasException(), Eq(true)); + ASSERT_TRUE(e.hasException()); } TEST(expected, T_fromCode_is_valid) { auto e = Expected::fromCode([]() -> int { return 42; }); - ASSERT_THAT(e.valid(), Eq(true)); + ASSERT_TRUE(e.valid()); } TEST(expected, T_fromCode_get) { auto e = Expected::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::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::fromCode([]() -> int { throw std::runtime_error("hello"); }); - ASSERT_THAT(e.hasException(), Eq(true)); + ASSERT_TRUE(e.hasException()); } TEST(expected, T_fromCode_E_has_exception_false) { auto e = Expected::fromCode([]() -> int { throw std::runtime_error("hello"); }); - ASSERT_THAT(e.hasException(), Eq(false)); + ASSERT_FALSE(e.hasException()); } TEST(expected, T_fromCode_E_has_derived_exception) { auto e = Expected::fromCode([]() -> int { throw std::runtime_error("hello"); }); - ASSERT_THAT(e.hasException(), Eq(true)); + ASSERT_TRUE(e.hasException()); } + + + //Expected getIntWithStdRuntimeError() { return Expected(); } Expected getNothing() { return Expected(); } @@ -105,7 +123,7 @@ Expected getNothing() { return Expected(); } TEST(expected_void, valid_when_valid_returns_true) { Expected 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 t = getNothing(); + auto v(t); + ASSERT_TRUE(v.valid()); + ASSERT_NO_THROW(v.get()); +} + TEST(expected_void, hasException_when_valid_returns_false) { Expected v = getNothing(); - ASSERT_THAT(v.hasException(), Eq(false)); + ASSERT_FALSE(v.hasException()); } - - - - - TEST(expected_void, void_fromException_is_not_valid) { auto e = Expected::fromException(std::runtime_error("hello")); @@ -201,3 +222,5 @@ TEST(expected_void, void_fromCode_E_has_derived_exception) auto e = Expected::fromCode(expected_void_throws_func); ASSERT_THAT(e.hasException(), Eq(true)); } + + diff --git a/tests/auto/mycase/tst_scopeguard.h b/src/core/test/tst_scopeguard.cpp similarity index 80% rename from tests/auto/mycase/tst_scopeguard.h rename to src/core/test/tst_scopeguard.cpp index 431e484..fb72c92 100644 --- a/tests/auto/mycase/tst_scopeguard.h +++ b/src/core/test/tst_scopeguard.cpp @@ -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); } diff --git a/src/icons/backups.png b/src/icons/backups.png deleted file mode 100644 index 41b14aa..0000000 Binary files a/src/icons/backups.png and /dev/null differ diff --git a/src/icons/information.png b/src/icons/information.png deleted file mode 100644 index 93c67f2..0000000 Binary files a/src/icons/information.png and /dev/null differ diff --git a/src/icons/server_add.png b/src/icons/server_add.png deleted file mode 100644 index 210979f..0000000 Binary files a/src/icons/server_add.png and /dev/null differ diff --git a/src/.gitignore b/src/pglab/.gitignore similarity index 100% rename from src/.gitignore rename to src/pglab/.gitignore diff --git a/src/pglab/ASyncDBConnection.cpp b/src/pglab/ASyncDBConnection.cpp new file mode 100644 index 0000000..4892327 --- /dev/null +++ b/src/pglab/ASyncDBConnection.cpp @@ -0,0 +1,174 @@ +#include "ASyncDBConnection.h" +#include "ScopeGuard.h" +#include + +using namespace boost::asio; + +namespace { + + class registerMetaTypes { + public: + registerMetaTypes() + { + qRegisterMetaType(); + qRegisterMetaType(); + } + } 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); +} diff --git a/src/pglab/ASyncDBConnection.h b/src/pglab/ASyncDBConnection.h new file mode 100644 index 0000000..60543e9 --- /dev/null +++ b/src/pglab/ASyncDBConnection.h @@ -0,0 +1,76 @@ +#ifndef ASYNCDBCONNECTION_H +#define ASYNCDBCONNECTION_H + +#include + +#include "Pgsql_Connection.h" +#include "Pgsql_Params.h" +#include "Pgsql_Result.h" +#include "Expected.h" +#include "ConnectionConfig.h" +#include +#include +#include +#include + +/** \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>, 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 diff --git a/src/ASyncWindow.cpp b/src/pglab/ASyncWindow.cpp similarity index 100% rename from src/ASyncWindow.cpp rename to src/pglab/ASyncWindow.cpp diff --git a/src/ASyncWindow.h b/src/pglab/ASyncWindow.h similarity index 100% rename from src/ASyncWindow.h rename to src/pglab/ASyncWindow.h diff --git a/src/BackupDialog.cpp b/src/pglab/BackupDialog.cpp similarity index 97% rename from src/BackupDialog.cpp rename to src/pglab/BackupDialog.cpp index 56a4c66..dd6062c 100644 --- a/src/BackupDialog.cpp +++ b/src/pglab/BackupDialog.cpp @@ -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 #include -#include - 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); } diff --git a/src/BackupDialog.h b/src/pglab/BackupDialog.h similarity index 100% rename from src/BackupDialog.h rename to src/pglab/BackupDialog.h diff --git a/src/BackupDialog.ui b/src/pglab/BackupDialog.ui similarity index 100% rename from src/BackupDialog.ui rename to src/pglab/BackupDialog.ui diff --git a/src/BackupRestore.cpp b/src/pglab/BackupRestore.cpp similarity index 98% rename from src/BackupRestore.cpp rename to src/pglab/BackupRestore.cpp index 801d582..5cbfe07 100644 --- a/src/BackupRestore.cpp +++ b/src/pglab/BackupRestore.cpp @@ -1,6 +1,6 @@ #include #include -#include "connectionconfig.h" +#include "ConnectionConfig.h" void setupEnvironment(const ConnectionConfig &cc) { diff --git a/src/pglab/CMakeLists.txt b/src/pglab/CMakeLists.txt new file mode 100644 index 0000000..ae14441 --- /dev/null +++ b/src/pglab/CMakeLists.txt @@ -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 + ) diff --git a/src/ConnectionConfig.cpp b/src/pglab/ConnectionConfig.cpp similarity index 99% rename from src/ConnectionConfig.cpp rename to src/pglab/ConnectionConfig.cpp index 7b14dbb..d6fcb21 100644 --- a/src/ConnectionConfig.cpp +++ b/src/pglab/ConnectionConfig.cpp @@ -1,4 +1,4 @@ -#include "connectionconfig.h" +#include "ConnectionConfig.h" #include "util.h" #include #include diff --git a/src/ConnectionConfig.h b/src/pglab/ConnectionConfig.h similarity index 100% rename from src/ConnectionConfig.h rename to src/pglab/ConnectionConfig.h diff --git a/src/ConnectionList.cpp b/src/pglab/ConnectionList.cpp similarity index 99% rename from src/ConnectionList.cpp rename to src/pglab/ConnectionList.cpp index 39eb6ed..c373474 100644 --- a/src/ConnectionList.cpp +++ b/src/pglab/ConnectionList.cpp @@ -1,5 +1,5 @@ #include "ConnectionList.h" -#include "scopeguard.h" +#include "ScopeGuard.h" #include "util.h" #include #include diff --git a/src/ConnectionList.h b/src/pglab/ConnectionList.h similarity index 100% rename from src/ConnectionList.h rename to src/pglab/ConnectionList.h diff --git a/src/ConnectionListModel.cpp b/src/pglab/ConnectionListModel.cpp similarity index 99% rename from src/ConnectionListModel.cpp rename to src/pglab/ConnectionListModel.cpp index 597ea13..dfb87c2 100644 --- a/src/ConnectionListModel.cpp +++ b/src/pglab/ConnectionListModel.cpp @@ -1,6 +1,6 @@ #include "ConnectionListModel.h" #include "ConnectionList.h" -#include "scopeguard.h" +#include "ScopeGuard.h" #include "util.h" #include diff --git a/src/ConnectionListModel.h b/src/pglab/ConnectionListModel.h similarity index 96% rename from src/ConnectionListModel.h rename to src/pglab/ConnectionListModel.h index acbfa31..78ce96a 100644 --- a/src/ConnectionListModel.h +++ b/src/pglab/ConnectionListModel.h @@ -6,8 +6,8 @@ #include -#include "connectionconfig.h" -#include "expected.h" +#include "ConnectionConfig.h" +#include "Expected.h" class ConnectionList; diff --git a/src/ConnectionManagerWindow.cpp b/src/pglab/ConnectionManagerWindow.cpp similarity index 97% rename from src/ConnectionManagerWindow.cpp rename to src/pglab/ConnectionManagerWindow.cpp index 5e431a5..cd5740a 100644 --- a/src/ConnectionManagerWindow.cpp +++ b/src/pglab/ConnectionManagerWindow.cpp @@ -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 #include #include - -#include "connectionlistmodel.h" +#include "ConnectionListModel.h" ConnectionManagerWindow::ConnectionManagerWindow(MasterController *master, QWidget *parent) : QMainWindow(parent) diff --git a/src/ConnectionManagerWindow.h b/src/pglab/ConnectionManagerWindow.h similarity index 100% rename from src/ConnectionManagerWindow.h rename to src/pglab/ConnectionManagerWindow.h diff --git a/src/ConnectionManagerWindow.ui b/src/pglab/ConnectionManagerWindow.ui similarity index 92% rename from src/ConnectionManagerWindow.ui rename to src/pglab/ConnectionManagerWindow.ui index c98eafd..225e2af 100644 --- a/src/ConnectionManagerWindow.ui +++ b/src/pglab/ConnectionManagerWindow.ui @@ -201,12 +201,12 @@ 0 0 800 - 23 + 24 - File + Fi&le @@ -240,7 +240,7 @@ - :/icons/server_add.png:/icons/server_add.png + :/icons/add_connection.png:/icons/add_connection.png Add Connection @@ -248,9 +248,9 @@ - - :/icons/server_delete.png - + + :/icons/delete_connection.png + :/icons/delete_connection.png:/icons/delete_connection.png Delete connection @@ -261,8 +261,9 @@ - - :/icons/server_go.png:/icons/server_go.png + + :/icons/open_query_window.png + Connect @@ -270,14 +271,14 @@ - Quit application + &Quit application - - :/icons/backups.png - + + :/icons/backup_database.png + :/icons/backups.png:/icons/backup_database.png Backup database @@ -286,7 +287,7 @@ - :/icons/server_edit.png + :/icons/manage_server.png diff --git a/src/DatabaseInspectorWidget.cpp b/src/pglab/DatabaseInspectorWidget.cpp similarity index 73% rename from src/DatabaseInspectorWidget.cpp rename to src/pglab/DatabaseInspectorWidget.cpp index 93d7f38..aa0be11 100644 --- a/src/DatabaseInspectorWidget.cpp +++ b/src/pglab/DatabaseInspectorWidget.cpp @@ -1,5 +1,5 @@ -#include "databaseinspectorwidget.h" -#include "ui_databaseinspectorwidget.h" +#include "DatabaseInspectorWidget.h" +#include "ui_DatabaseInspectorWidget.h" DatabaseInspectorWidget::DatabaseInspectorWidget(QWidget *parent) : QWidget(parent), diff --git a/src/DatabaseInspectorWidget.h b/src/pglab/DatabaseInspectorWidget.h similarity index 100% rename from src/DatabaseInspectorWidget.h rename to src/pglab/DatabaseInspectorWidget.h diff --git a/src/DatabaseInspectorWidget.ui b/src/pglab/DatabaseInspectorWidget.ui similarity index 100% rename from src/DatabaseInspectorWidget.ui rename to src/pglab/DatabaseInspectorWidget.ui diff --git a/src/DatabaseWindow.cpp b/src/pglab/DatabaseWindow.cpp similarity index 86% rename from src/DatabaseWindow.cpp rename to src/pglab/DatabaseWindow.cpp index 5494534..4aab48e 100644 --- a/src/DatabaseWindow.cpp +++ b/src/pglab/DatabaseWindow.cpp @@ -1,28 +1,23 @@ -#include "databasewindow.h" -#include "ui_databasewindow.h" +#include "DatabaseWindow.h" +#include "ui_DatabaseWindow.h" #include +#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; } diff --git a/src/DatabaseWindow.h b/src/pglab/DatabaseWindow.h similarity index 96% rename from src/DatabaseWindow.h rename to src/pglab/DatabaseWindow.h index 6addd3d..d5a87d7 100644 --- a/src/DatabaseWindow.h +++ b/src/pglab/DatabaseWindow.h @@ -1,7 +1,7 @@ #ifndef DATABASEWINDOW_H #define DATABASEWINDOW_H -#include "asyncdbconnection.h" +#include "ASyncDBConnection.h" #include "tsqueue.h" #include diff --git a/src/DatabaseWindow.ui b/src/pglab/DatabaseWindow.ui similarity index 100% rename from src/DatabaseWindow.ui rename to src/pglab/DatabaseWindow.ui diff --git a/src/DatabasesTableModel.cpp b/src/pglab/DatabasesTableModel.cpp similarity index 94% rename from src/DatabasesTableModel.cpp rename to src/pglab/DatabasesTableModel.cpp index 864625e..0047af1 100644 --- a/src/DatabasesTableModel.cpp +++ b/src/pglab/DatabasesTableModel.cpp @@ -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; diff --git a/src/DatabasesTableModel.h b/src/pglab/DatabasesTableModel.h similarity index 84% rename from src/DatabasesTableModel.h rename to src/pglab/DatabasesTableModel.h index 55cde5d..cc15528 100644 --- a/src/DatabasesTableModel.h +++ b/src/pglab/DatabasesTableModel.h @@ -1,10 +1,10 @@ -#ifndef DATABASESTABLEMODEL_H +#ifndef DATABASESTABLEMODEL_H #define DATABASESTABLEMODEL_H #include 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; }; diff --git a/src/Doxyfile b/src/pglab/Doxyfile similarity index 100% rename from src/Doxyfile rename to src/pglab/Doxyfile diff --git a/src/ExplainTreeModelItem.cpp b/src/pglab/ExplainTreeModelItem.cpp similarity index 99% rename from src/ExplainTreeModelItem.cpp rename to src/pglab/ExplainTreeModelItem.cpp index deacd17..f756b1f 100644 --- a/src/ExplainTreeModelItem.cpp +++ b/src/pglab/ExplainTreeModelItem.cpp @@ -1,4 +1,4 @@ -#include "explaintreemodelitem.h" +#include "ExplainTreeModelItem.h" #include "json/json.h" #include diff --git a/src/ExplainTreeModelItem.h b/src/pglab/ExplainTreeModelItem.h similarity index 100% rename from src/ExplainTreeModelItem.h rename to src/pglab/ExplainTreeModelItem.h diff --git a/src/pglab/GlobalIoService.cpp b/src/pglab/GlobalIoService.cpp new file mode 100644 index 0000000..99ddd2b --- /dev/null +++ b/src/pglab/GlobalIoService.cpp @@ -0,0 +1,7 @@ +#include "GlobalIoService.h" + +std::shared_ptr getGlobalAsioIoService() +{ + static auto ios = std::make_shared(); + return ios; +} diff --git a/src/pglab/GlobalIoService.h b/src/pglab/GlobalIoService.h new file mode 100644 index 0000000..5e92327 --- /dev/null +++ b/src/pglab/GlobalIoService.h @@ -0,0 +1,6 @@ +#pragma once + +#include +#include + +std::shared_ptr getGlobalAsioIoService(); diff --git a/src/MainWindow.cpp b/src/pglab/MainWindow.cpp similarity index 96% rename from src/MainWindow.cpp rename to src/pglab/MainWindow.cpp index 76300f1..aa4f038 100644 --- a/src/MainWindow.cpp +++ b/src/pglab/MainWindow.cpp @@ -1,17 +1,16 @@ #include "MainWindow.h" -#include "ui_mainwindow.h" +#include "ui_MainWindow.h" #include #include #include #include #include -#include #include #include #include #include -#include +#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." )); } diff --git a/src/MainWindow.h b/src/pglab/MainWindow.h similarity index 93% rename from src/MainWindow.h rename to src/pglab/MainWindow.h index 13edb47..4359dad 100644 --- a/src/MainWindow.h +++ b/src/pglab/MainWindow.h @@ -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 #include "ASyncWindow.h" #include #include #include -#include "PgsqlConn.h" +#include "Pgsql_Connection.h" #include #include #include @@ -41,7 +41,7 @@ private: Ui::MainWindow *ui; ConnectionConfig m_config; - OpenDatabase *m_database; + OpenDatabase *m_database = nullptr; MasterController *m_masterController; diff --git a/src/MainWindow.ui b/src/pglab/MainWindow.ui similarity index 87% rename from src/MainWindow.ui rename to src/pglab/MainWindow.ui index 7a19461..d3e2cf3 100644 --- a/src/MainWindow.ui +++ b/src/pglab/MainWindow.ui @@ -45,12 +45,12 @@ 0 0 993 - 22 + 24 - File + Fi&le @@ -69,7 +69,7 @@ - Query + &Query @@ -79,7 +79,7 @@ - Window + Wi&ndow @@ -126,7 +126,7 @@ :/icons/folder.png:/icons/folder.png - Load SQL + &Load SQL Ctrl+O @@ -138,7 +138,7 @@ :/icons/script_save.png:/icons/script_save.png - Save SQL + &Save SQL Ctrl+S @@ -150,7 +150,7 @@ :/icons/table_save.png:/icons/table_save.png - Export data + &Export data @@ -160,7 +160,7 @@ - Close + &Close Ctrl+F4 @@ -168,12 +168,12 @@ - - :/icons/information.png - + + :/icons/about.png + :/icons/information.png:/icons/about.png - About + &About @@ -183,7 +183,7 @@ - Execute queries + &Execute queries Execute the (selected) queries @@ -199,7 +199,7 @@ - Cancel + &Cancel Alt+Pause @@ -211,7 +211,7 @@ :/icons/lightbulb.png:/icons/lightbulb.png - Explain Analyze + Ex&plain Analyze Shift+F7 @@ -219,22 +219,22 @@ - Save SQL as + Sa&ve SQL as - Save copy of SQL as + Save copy &of SQL as - - :/icons/page_white_add.png - + + :/icons/new_query_tab.png + :/icons/page_white_add.png:/icons/new_query_tab.png - New SQL + &New SQL Ctrl+N @@ -247,7 +247,7 @@ - Explain + E&xplain Explain the (selected) query @@ -258,7 +258,7 @@ - Show connection manager + &Show connection manager @@ -268,7 +268,7 @@ - Copy + &Copy Ctrl+C @@ -281,7 +281,7 @@ - Copy as C-string + Copy as C-&string Ctrl+Alt+C diff --git a/src/MasterController.cpp b/src/pglab/MasterController.cpp similarity index 100% rename from src/MasterController.cpp rename to src/pglab/MasterController.cpp diff --git a/src/MasterController.h b/src/pglab/MasterController.h similarity index 97% rename from src/MasterController.h rename to src/pglab/MasterController.h index 68b4bd1..562e9ee 100644 --- a/src/MasterController.h +++ b/src/pglab/MasterController.h @@ -2,8 +2,10 @@ #define MASTERCONTROLLER_H #include +#include #include + class ConnectionConfig; class ConnectionList; class ConnectionListModel; @@ -30,7 +32,7 @@ public: void openSqlWindowForConnection(int connection_index); void openServerWindowForConnection(int connection_index); void openBackupDlgForConnection(int connection_index); - + signals: public slots: @@ -39,6 +41,7 @@ private: ConnectionList *m_connectionList = nullptr; ConnectionListModel *m_connectionListModel = nullptr; ConnectionManagerWindow *m_connectionManagerWindow = nullptr; + }; #endif // MASTERCONTROLLER_H diff --git a/src/OpenDatabase.cpp b/src/pglab/OpenDatabase.cpp similarity index 70% rename from src/OpenDatabase.cpp rename to src/pglab/OpenDatabase.cpp index 2cb0832..cc04b33 100644 --- a/src/OpenDatabase.cpp +++ b/src/pglab/OpenDatabase.cpp @@ -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::createOpenDatabase(const ConnectionConfig &cfg) { OpenDatabase *odb = new OpenDatabase(cfg, nullptr); if (odb->Init()) { + return odb; } - return odb; //return Expected::fromException(std::out_of_range("Invalid row")); + return Expected::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; } diff --git a/src/OpenDatabase.h b/src/pglab/OpenDatabase.h similarity index 80% rename from src/OpenDatabase.h rename to src/pglab/OpenDatabase.h index 19de20f..4e1bd39 100644 --- a/src/OpenDatabase.h +++ b/src/pglab/OpenDatabase.h @@ -1,11 +1,11 @@ -#ifndef OPENDATABASE_H +#ifndef OPENDATABASE_H #define OPENDATABASE_H #include -#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; diff --git a/src/ParamListModel.cpp b/src/pglab/ParamListModel.cpp similarity index 100% rename from src/ParamListModel.cpp rename to src/pglab/ParamListModel.cpp diff --git a/src/ParamListModel.h b/src/pglab/ParamListModel.h similarity index 94% rename from src/ParamListModel.h rename to src/pglab/ParamListModel.h index 11acfc3..7363bde 100644 --- a/src/ParamListModel.h +++ b/src/pglab/ParamListModel.h @@ -1,4 +1,4 @@ -#ifndef PARAMLISTMODEL_H +#ifndef PARAMLISTMODEL_H #define PARAMLISTMODEL_H #include @@ -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) diff --git a/src/ParamTypeDelegate.cpp b/src/pglab/ParamTypeDelegate.cpp similarity index 100% rename from src/ParamTypeDelegate.cpp rename to src/pglab/ParamTypeDelegate.cpp diff --git a/src/ParamTypeDelegate.h b/src/pglab/ParamTypeDelegate.h similarity index 100% rename from src/ParamTypeDelegate.h rename to src/pglab/ParamTypeDelegate.h diff --git a/src/PgAuthId.cpp b/src/pglab/PgAuthId.cpp similarity index 100% rename from src/PgAuthId.cpp rename to src/pglab/PgAuthId.cpp diff --git a/src/PgAuthId.h b/src/pglab/PgAuthId.h similarity index 95% rename from src/PgAuthId.h rename to src/pglab/PgAuthId.h index bea69e6..c71c4f8 100644 --- a/src/PgAuthId.h +++ b/src/pglab/PgAuthId.h @@ -1,7 +1,7 @@ #ifndef PGAUTHID_H #define PGAUTHID_H -#include +#include #include #include diff --git a/src/PgAuthIdContainer.cpp b/src/pglab/PgAuthIdContainer.cpp similarity index 87% rename from src/PgAuthIdContainer.cpp rename to src/pglab/PgAuthIdContainer.cpp index 3859a41..6c3a4a7 100644 --- a/src/PgAuthIdContainer.cpp +++ b/src/pglab/PgAuthIdContainer.cpp @@ -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(cat) {} diff --git a/src/PgAuthIdContainer.h b/src/pglab/PgAuthIdContainer.h similarity index 78% rename from src/PgAuthIdContainer.h rename to src/pglab/PgAuthIdContainer.h index 8787933..455681e 100644 --- a/src/PgAuthIdContainer.h +++ b/src/pglab/PgAuthIdContainer.h @@ -1,4 +1,4 @@ -#ifndef PGAUTHIDCONTAINER_H +#ifndef PGAUTHIDCONTAINER_H #define PGAUTHIDCONTAINER_H #include @@ -14,7 +14,7 @@ namespace Pgsql { class PgAuthIdContainer: public PgContainer { public: - explicit PgAuthIdContainer(PgsqlDatabaseCatalogue *cat); + explicit PgAuthIdContainer(PgDatabaseCatalogue *cat); std::string getLoadQuery() const; void load(const Pgsql::Result &res); diff --git a/src/PgClass.cpp b/src/pglab/PgClass.cpp similarity index 56% rename from src/PgClass.cpp rename to src/pglab/PgClass.cpp index 3d066ad..c4d74ed 100644 --- a/src/PgClass.cpp +++ b/src/pglab/PgClass.cpp @@ -1,3 +1,3 @@ -#include "pgclass.h" +#include "PgClass.h" PgClass::PgClass() = default; diff --git a/src/PgClass.h b/src/pglab/PgClass.h similarity index 94% rename from src/PgClass.h rename to src/pglab/PgClass.h index acdec0d..05f0c64 100644 --- a/src/PgClass.h +++ b/src/pglab/PgClass.h @@ -2,7 +2,7 @@ #define PGCLASS_H #include -#include +#include class PgClass { public: diff --git a/src/PgContainer.h b/src/pglab/PgContainer.h similarity index 86% rename from src/PgContainer.h rename to src/pglab/PgContainer.h index 835b848..21e9e0d 100644 --- a/src/PgContainer.h +++ b/src/pglab/PgContainer.h @@ -1,18 +1,18 @@ -#ifndef PGCONTAINER_H +#ifndef PGCONTAINER_H #define PGCONTAINER_H #include #include -#include +#include -class PgsqlDatabaseCatalogue; +class PgDatabaseCatalogue; template class PgContainer { public: using t_Container = std::vector; ///< 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; diff --git a/src/PgDatabase.cpp b/src/pglab/PgDatabase.cpp similarity index 100% rename from src/PgDatabase.cpp rename to src/pglab/PgDatabase.cpp diff --git a/src/PgDatabase.h b/src/pglab/PgDatabase.h similarity index 95% rename from src/PgDatabase.h rename to src/pglab/PgDatabase.h index 724e2b9..679c0dd 100644 --- a/src/PgDatabase.h +++ b/src/pglab/PgDatabase.h @@ -2,7 +2,7 @@ #define PGDATABASE_H #include -#include +#include class PgDatabase { public: diff --git a/src/PgsqlDatabaseCatalogue.cpp b/src/pglab/PgDatabaseCatalogue.cpp similarity index 67% rename from src/PgsqlDatabaseCatalogue.cpp rename to src/pglab/PgDatabaseCatalogue.cpp index fafe34e..ca53c0c 100644 --- a/src/PgsqlDatabaseCatalogue.cpp +++ b/src/pglab/PgDatabaseCatalogue.cpp @@ -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; } diff --git a/src/PgsqlDatabaseCatalogue.h b/src/pglab/PgDatabaseCatalogue.h similarity index 72% rename from src/PgsqlDatabaseCatalogue.h rename to src/pglab/PgDatabaseCatalogue.h index 0fa8162..1911708 100644 --- a/src/PgsqlDatabaseCatalogue.h +++ b/src/pglab/PgDatabaseCatalogue.h @@ -1,7 +1,7 @@ #ifndef PGSQLDATABASECATALOGUE_H #define PGSQLDATABASECATALOGUE_H -#include +#include #include #include @@ -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 diff --git a/src/PgDatabaseContainer.cpp b/src/pglab/PgDatabaseContainer.cpp similarity index 87% rename from src/PgDatabaseContainer.cpp rename to src/pglab/PgDatabaseContainer.cpp index 927d93d..ba5b729 100644 --- a/src/PgDatabaseContainer.cpp +++ b/src/pglab/PgDatabaseContainer.cpp @@ -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(cat) {} diff --git a/src/PgDatabaseContainer.h b/src/pglab/PgDatabaseContainer.h similarity index 77% rename from src/PgDatabaseContainer.h rename to src/pglab/PgDatabaseContainer.h index c2b711e..d49c4f0 100644 --- a/src/PgDatabaseContainer.h +++ b/src/pglab/PgDatabaseContainer.h @@ -1,4 +1,4 @@ -#ifndef PGDATABASECONTAINER_H +#ifndef PGDATABASECONTAINER_H #define PGDATABASECONTAINER_H #include @@ -14,7 +14,7 @@ namespace Pgsql { class PgDatabaseContainer: public PgContainer { public: - explicit PgDatabaseContainer(PgsqlDatabaseCatalogue *cat); + explicit PgDatabaseContainer(PgDatabaseCatalogue *cat); std::string getLoadQuery() const; void load(const Pgsql::Result &res); diff --git a/src/PgNamespace.cpp b/src/pglab/PgNamespace.cpp similarity index 58% rename from src/PgNamespace.cpp rename to src/pglab/PgNamespace.cpp index a1d6590..c395bf5 100644 --- a/src/PgNamespace.cpp +++ b/src/pglab/PgNamespace.cpp @@ -1,4 +1,4 @@ -#include "pgnamespace.h" +#include "PgNamespace.h" PgNamespace::PgNamespace() = default; diff --git a/src/PgNamespace.h b/src/pglab/PgNamespace.h similarity index 87% rename from src/PgNamespace.h rename to src/pglab/PgNamespace.h index 2c33805..f406c20 100644 --- a/src/PgNamespace.h +++ b/src/pglab/PgNamespace.h @@ -2,7 +2,7 @@ #define PGNAMESPACE_H #include -#include +#include class PgNamespace { diff --git a/src/pglab/PgType.cpp b/src/pglab/PgType.cpp new file mode 100644 index 0000000..ba81860 --- /dev/null +++ b/src/pglab/PgType.cpp @@ -0,0 +1,5 @@ +#include "PgType.h" +#include "Pgsql_Connection.h" + +PgType::PgType() = default; + diff --git a/src/PgType.h b/src/pglab/PgType.h similarity index 98% rename from src/PgType.h rename to src/pglab/PgType.h index 1246700..b39b42d 100644 --- a/src/PgType.h +++ b/src/pglab/PgType.h @@ -2,7 +2,7 @@ #define PGTYPE_H #include -#include +#include class PgType { public: diff --git a/src/PgTypeContainer.cpp b/src/pglab/PgTypeContainer.cpp similarity index 96% rename from src/PgTypeContainer.cpp rename to src/pglab/PgTypeContainer.cpp index f1538c6..311e112 100644 --- a/src/PgTypeContainer.cpp +++ b/src/pglab/PgTypeContainer.cpp @@ -1,8 +1,8 @@ -#include "pgtypecontainer.h" -#include "PgsqlConn.h" +#include "PgTypeContainer.h" +#include "Pgsql_Connection.h" #include -PgTypeContainer::PgTypeContainer(PgsqlDatabaseCatalogue *cat) +PgTypeContainer::PgTypeContainer(PgDatabaseCatalogue *cat) : PgContainer(cat) {} diff --git a/src/PgTypeContainer.h b/src/pglab/PgTypeContainer.h similarity index 91% rename from src/PgTypeContainer.h rename to src/pglab/PgTypeContainer.h index 7c5656d..af2cf84 100644 --- a/src/PgTypeContainer.h +++ b/src/pglab/PgTypeContainer.h @@ -1,8 +1,8 @@ -#ifndef PGTYPECONTAINER_H +#ifndef PGTYPECONTAINER_H #define PGTYPECONTAINER_H #include -#include "pgtype.h" +#include "PgType.h" #include "PgContainer.h" namespace Pgsql { @@ -15,7 +15,7 @@ class PgTypeContainer: public PgContainer { public: // using t_Types = std::vector; ///< 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(); } diff --git a/src/ProcessStdioWidget.cpp b/src/pglab/ProcessStdioWidget.cpp similarity index 100% rename from src/ProcessStdioWidget.cpp rename to src/pglab/ProcessStdioWidget.cpp diff --git a/src/ProcessStdioWidget.h b/src/pglab/ProcessStdioWidget.h similarity index 100% rename from src/ProcessStdioWidget.h rename to src/pglab/ProcessStdioWidget.h diff --git a/src/ProcessStdioWidget.ui b/src/pglab/ProcessStdioWidget.ui similarity index 100% rename from src/ProcessStdioWidget.ui rename to src/pglab/ProcessStdioWidget.ui diff --git a/src/QueryExplainModel.cpp b/src/pglab/QueryExplainModel.cpp similarity index 97% rename from src/QueryExplainModel.cpp rename to src/pglab/QueryExplainModel.cpp index 5e0a27d..67ccfca 100644 --- a/src/QueryExplainModel.cpp +++ b/src/pglab/QueryExplainModel.cpp @@ -1,6 +1,7 @@ -#include "queryexplainmodel.h" +#include "QueryExplainModel.h" #include #include +#include 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); } diff --git a/src/QueryExplainModel.h b/src/pglab/QueryExplainModel.h similarity index 96% rename from src/QueryExplainModel.h rename to src/pglab/QueryExplainModel.h index 721c608..0aa318a 100644 --- a/src/QueryExplainModel.h +++ b/src/pglab/QueryExplainModel.h @@ -2,7 +2,7 @@ #include #include -#include "explaintreemodelitem.h" +#include "ExplainTreeModelItem.h" /** \brief Model class for displaying the explain of a query in a tree like format. */ diff --git a/src/QueryResultModel.cpp b/src/pglab/QueryResultModel.cpp similarity index 98% rename from src/QueryResultModel.cpp rename to src/pglab/QueryResultModel.cpp index 623d2be..9371ffd 100644 --- a/src/QueryResultModel.cpp +++ b/src/pglab/QueryResultModel.cpp @@ -1,4 +1,4 @@ -#include "queryresultmodel.h" +#include "QueryResultModel.h" #include "Pgsql_declare.h" #include #include diff --git a/src/QueryResultModel.h b/src/pglab/QueryResultModel.h similarity index 96% rename from src/QueryResultModel.h rename to src/pglab/QueryResultModel.h index f137293..ed8f21a 100644 --- a/src/QueryResultModel.h +++ b/src/pglab/QueryResultModel.h @@ -2,7 +2,7 @@ #define QUERYRESULTMODEL_H #include -#include "PgsqlConn.h" +#include "Pgsql_Connection.h" class QueryResultModel : public QAbstractTableModel { diff --git a/src/QueryTab.cpp b/src/pglab/QueryTab.cpp similarity index 72% rename from src/QueryTab.cpp rename to src/pglab/QueryTab.cpp index 31d41c3..6d4d10f 100644 --- a/src/QueryTab.cpp +++ b/src/pglab/QueryTab.cpp @@ -1,10 +1,9 @@ -#include "querytab.h" -#include "ui_querytab.h" - +#include "QueryTab.h" +#include "ui_QueryTab.h" #include "SqlSyntaxHighlighter.h" - #include #include + #include #include #include @@ -12,14 +11,14 @@ #include #include #include -#include "explaintreemodelitem.h" +#include "ExplainTreeModelItem.h" #include "json/json.h" #include "MainWindow.h" #include "OpenDatabase.h" -#include "pgtypecontainer.h" -#include "pgsqldatabasecatalogue.h" +#include "PgTypeContainer.h" +#include "PgDatabaseCatalogue.h" #include "util.h" - +#include "GlobalIoService.h" QueryParamListController::QueryParamListController(QTableView *tv, OpenDatabase *opendb, QWidget *parent) @@ -27,7 +26,9 @@ QueryParamListController::QueryParamListController(QTableView *tv, , paramTableView(tv) , m_openDatabase(opendb) { - m_typeDelegate.setTypeSelectionModel(opendb->typeSelectionModel()); + if (opendb) { + m_typeDelegate.setTypeSelectionModel(opendb->typeSelectionModel()); + } paramTableView->setModel(&m_paramList); paramTableView->setItemDelegateForColumn(1, &m_typeDelegate); @@ -44,6 +45,13 @@ Pgsql::Params QueryParamListController::params() const return params; } +bool QueryParamListController::empty() const +{ + + return m_paramList.rowCount() == 0; +} + + void QueryParamListController::on_addParam() { m_paramList.insertRows(m_paramList.rowCount(), 1); @@ -61,43 +69,39 @@ void QueryParamListController::on_removeParam() QueryTab::QueryTab(MainWindow *win, QWidget *parent) : QWidget(parent), ui(new Ui::QueryTab), - m_win(win) + m_win(win), + m_dbConnection(*getGlobalAsioIoService()) { ui->setupUi(this); - m_dbConnection.setStateCallback([this](ASyncDBConnection::State st) - { - m_win->QueueTask([this, st]() { connectionStateChanged(st); }); - }); - - m_dbConnection.setNoticeCallback([this](Pgsql::ErrorDetails details) - { - m_win->QueueTask([this, details]() { receiveNotice(details); }); - }); - + connect(&m_dbConnection, &ASyncDBConnection::onStateChanged, this, &QueryTab::connectionStateChanged); + connect(&m_dbConnection, &ASyncDBConnection::onNotice, this, &QueryTab::receiveNotice); + QFont font; font.setFamily("Source Code Pro"); font.setFixedPitch(true); font.setPointSize(10); ui->queryEdit->setFont(font); - OpenDatabase* open_database = m_win->getDatabase(); - auto cat = open_database->catalogue(); - highlighter = new SqlSyntaxHighlighter(ui->queryEdit->document()); - highlighter->setTypes(cat->types()); + OpenDatabase* open_database = m_win->getDatabase(); + if (open_database) { + auto cat = open_database->catalogue(); + highlighter->setTypes(cat->types()); + } connect(ui->queryEdit, &QPlainTextEdit::textChanged, this, &QueryTab::queryTextChanged); m_queryParamListController = new QueryParamListController(ui->paramTableView, open_database, this); - connect(ui->addButton, &QPushButton::clicked, m_queryParamListController, &QueryParamListController::on_addParam); - connect(ui->removeButton, &QPushButton::clicked, m_queryParamListController, &QueryParamListController::on_removeParam); + connect(ui->addButton, &QPushButton::clicked, m_queryParamListController, + &QueryParamListController::on_addParam); + connect(ui->removeButton, &QPushButton::clicked, m_queryParamListController, + &QueryParamListController::on_removeParam); } QueryTab::~QueryTab() { m_dbConnection.closeConnection(); - m_dbConnection.setStateCallback(nullptr); delete ui; } @@ -198,12 +202,20 @@ void QueryTab::execute() std::string cmd = getCommand(); m_stopwatch.start(); - m_dbConnection.send(cmd, - m_queryParamListController->params(), - [this](std::shared_ptr res, qint64 elapsedms) - { - m_win->QueueTask([this, res, elapsedms]() { query_ready(res, elapsedms); }); - }); + + if (m_queryParamListController->empty()) + m_dbConnection.send(cmd, + [this](Expected> res, qint64 elapsedms) + { + m_win->QueueTask([this, res, elapsedms]() { query_ready(res, elapsedms); }); + }); + else + m_dbConnection.send(cmd, + m_queryParamListController->params(), + [this](Expected> res, qint64 elapsedms) + { + m_win->QueueTask([this, res, elapsedms]() { query_ready(res, elapsedms); }); + }); } } @@ -222,10 +234,11 @@ void QueryTab::explain(bool analyze) m_stopwatch.start(); std::string cmd = "EXPLAIN (" + analyze_str + "VERBOSE, BUFFERS, FORMAT JSON) " + getCommand(); m_dbConnection.send(cmd, - [this](std::shared_ptr res, qint64 ) + [this](Expected> exp_res, qint64 ) { - if (res) { + if (exp_res.valid()) { // Process explain data seperately + auto res = exp_res.get(); std::thread([this,res]() { std::shared_ptr explain; @@ -287,15 +300,14 @@ bool QueryTab::saveSqlTo(const QString &filename) QString text = ui->queryEdit->toPlainText(); stream << text; /* - - QTextDocument *doc = ui->queryEdit->document(); QTextBlock block = doc->firstBlock(); while (stream.status() == QTextStream::Ok && block.isValid()) { QString plain = block.text(); stream << plain << "\n"; block = block.next(); - }*/ + } +*/ stream.flush(); if (stream.status() == QTextStream::Ok) { @@ -471,77 +483,83 @@ void QueryTab::setTabCaption(const QString &caption, const QString &tooltip) } -void QueryTab::query_ready(std::shared_ptr dbres, qint64 elapsedms) +void QueryTab::query_ready(Expected> exp_res, qint64 elapsedms) { - if (dbres) { - addLog("query_ready with result"); - auto st = dbres->resultStatus(); - if (st == PGRES_TUPLES_OK) { - //int n_rows = dbres->getRows(); - //QString rowcount_str = QString("rows: %1").arg(dbres->getRows()); + if (exp_res.valid()) { + auto dbres = exp_res.get(); + if (dbres) { + addLog("query_ready with result"); + auto st = dbres->resultStatus(); + if (st == PGRES_TUPLES_OK) { + //int n_rows = dbres->getRows(); + //QString rowcount_str = QString("rows: %1").arg(dbres->getRows()); - auto result_model = std::make_shared(nullptr , dbres); - TuplesResultWidget *trw = new TuplesResultWidget; - trw->setResult(result_model, elapsedms); - resultList.push_back(trw); - ui->tabWidget->addTab(trw, "Data"); - if (resultList.size() == 1) - ui->tabWidget->setCurrentWidget(trw); + auto result_model = std::make_shared(nullptr , dbres); + TuplesResultWidget *trw = new TuplesResultWidget; + trw->setResult(result_model, elapsedms); + resultList.push_back(trw); + ui->tabWidget->addTab(trw, "Data"); + if (resultList.size() == 1) + ui->tabWidget->setCurrentWidget(trw); - } - else { - if (st == PGRES_COMMAND_OK) { - int tuples_affected = dbres->tuplesAffected(); - QString msg; - if (tuples_affected >= 0) - msg = tr("Query returned succesfully: %1 rows affected, execution time %2") - .arg(QString::number(tuples_affected)) - .arg(msfloatToHumanReadableString(elapsedms)); - else - msg = tr("Query returned succesfully, execution time %1") - .arg(msfloatToHumanReadableString(elapsedms)); + } + else { + if (st == PGRES_COMMAND_OK) { + int tuples_affected = dbres->tuplesAffected(); + QString msg; + if (tuples_affected >= 0) + msg = tr("Query returned succesfully: %1 rows affected, execution time %2") + .arg(QString::number(tuples_affected)) + .arg(msfloatToHumanReadableString(elapsedms)); + else + msg = tr("Query returned succesfully, execution time %1") + .arg(msfloatToHumanReadableString(elapsedms)); - ui->messagesEdit->append(msg); + ui->messagesEdit->append(msg); - ui->tabWidget->setCurrentWidget(ui->messageTab); - } - else { -// if (st == PGRES_EMPTY_QUERY) { -// statusBar()->showMessage(tr("Empty query.")); -// } -// else if (st == PGRES_COPY_OUT) { -// statusBar()->showMessage(tr("COPY OUT.")); -// } -// else if (st == PGRES_COPY_IN) { -// statusBar()->showMessage(tr("COPY IN.")); -// } -// else if (st == PGRES_BAD_RESPONSE) { -// statusBar()->showMessage(tr("BAD RESPONSE.")); -// } -// else if (st == PGRES_NONFATAL_ERROR) { -// statusBar()->showMessage(tr("NON FATAL ERROR.")); -// } -// else if (st == PGRES_FATAL_ERROR) { -// statusBar()->showMessage(tr("FATAL ERROR.")); -// } -// else if (st == PGRES_COPY_BOTH) { -// statusBar()->showMessage(tr("COPY BOTH shouldn't happen is for replication.")); -// } -// else if (st == PGRES_SINGLE_TUPLE) { -// statusBar()->showMessage(tr("SINGLE TUPLE result.")); -// } -// else { -// statusBar()->showMessage(tr("No tuples returned, possibly an error...")); -// } - ui->tabWidget->setCurrentWidget(ui->messageTab); - receiveNotice(dbres->diagDetails()); - } - } - } - else { - m_stopwatch.stop(); - addLog("query_ready with NO result"); - } + ui->tabWidget->setCurrentWidget(ui->messageTab); + } + else { + // if (st == PGRES_EMPTY_QUERY) { + // statusBar()->showMessage(tr("Empty query.")); + // } + // else if (st == PGRES_COPY_OUT) { + // statusBar()->showMessage(tr("COPY OUT.")); + // } + // else if (st == PGRES_COPY_IN) { + // statusBar()->showMessage(tr("COPY IN.")); + // } + // else if (st == PGRES_BAD_RESPONSE) { + // statusBar()->showMessage(tr("BAD RESPONSE.")); + // } + // else if (st == PGRES_NONFATAL_ERROR) { + // statusBar()->showMessage(tr("NON FATAL ERROR.")); + // } + // else if (st == PGRES_FATAL_ERROR) { + // statusBar()->showMessage(tr("FATAL ERROR.")); + // } + // else if (st == PGRES_COPY_BOTH) { + // statusBar()->showMessage(tr("COPY BOTH shouldn't happen is for replication.")); + // } + // else if (st == PGRES_SINGLE_TUPLE) { + // statusBar()->showMessage(tr("SINGLE TUPLE result.")); + // } + // else { + // statusBar()->showMessage(tr("No tuples returned, possibly an error...")); + // } + ui->tabWidget->setCurrentWidget(ui->messageTab); + receiveNotice(dbres->diagDetails()); + } + } + } + else { + m_stopwatch.stop(); + addLog("query_ready with NO result"); + } + } + else { + // we have an error + } } void QueryTab::clearResult() diff --git a/src/QueryTab.h b/src/pglab/QueryTab.h similarity index 85% rename from src/QueryTab.h rename to src/pglab/QueryTab.h index e0ed32b..d8b973e 100644 --- a/src/QueryTab.h +++ b/src/pglab/QueryTab.h @@ -1,11 +1,11 @@ #ifndef QUERYTAB_H #define QUERYTAB_H -#include "asyncdbconnection.h" +#include "ASyncDBConnection.h" #include "ParamListModel.h" #include "ParamTypeDelegate.h" -#include "queryresultmodel.h" -#include "queryexplainmodel.h" +#include "QueryResultModel.h" +#include "QueryExplainModel.h" #include "stopwatch.h" #include "tuplesresultwidget.h" @@ -33,6 +33,7 @@ public: QueryParamListController(QTableView *tv, OpenDatabase *opendb, QWidget *parent); Pgsql::Params params() const; + bool empty() const; public slots: void on_addParam(); void on_removeParam(); @@ -73,14 +74,6 @@ public: bool isNew() const { return m_new; } private: -// struct ResultTab { -// public: -// std::shared_ptr resultModel; -// std::shared_ptr tuplesResult; -//// ResultTab(std::shared_ptr rm, Ui::TuplesResult *tr) -//// : resultModel(rm), tuplesResult(tr) -//// {} -// }; using ResultTabContainer = std::vector; Ui::QueryTab *ui; @@ -112,7 +105,7 @@ private: std::string getCommand() const; void explain_ready(ExplainRoot::SPtr explain); - void query_ready(std::shared_ptr dbres, qint64 elapsedms); + void query_ready(Expected> dbres, qint64 elapsedms); QTabWidget *getTabWidget(); void setTabCaption(const QString &caption, const QString &tooltip); diff --git a/src/QueryTab.ui b/src/pglab/QueryTab.ui similarity index 57% rename from src/QueryTab.ui rename to src/pglab/QueryTab.ui index 4c459db..ccac5ac 100644 --- a/src/QueryTab.ui +++ b/src/pglab/QueryTab.ui @@ -15,101 +15,98 @@ - + Qt::Vertical - - - - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - 0 + + + Qt::Horizontal + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::StyledPanel - - 0 + + QFrame::Raised - - 0 + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Add + + + + + + + Remove + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + true - - 0 - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - 6 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Add - - - - - - - Remove - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - true - - - - - - - + + + + diff --git a/src/RolesTableModel.cpp b/src/pglab/RolesTableModel.cpp similarity index 100% rename from src/RolesTableModel.cpp rename to src/pglab/RolesTableModel.cpp diff --git a/src/RolesTableModel.h b/src/pglab/RolesTableModel.h similarity index 100% rename from src/RolesTableModel.h rename to src/pglab/RolesTableModel.h diff --git a/src/ServerWindow.cpp b/src/pglab/ServerWindow.cpp similarity index 93% rename from src/ServerWindow.cpp rename to src/pglab/ServerWindow.cpp index a08075e..0d2f6cb 100644 --- a/src/ServerWindow.cpp +++ b/src/pglab/ServerWindow.cpp @@ -1,9 +1,9 @@ -#include "ServerWindow.h" +#include "ServerWindow.h" #include "ui_ServerWindow.h" #include "OpenDatabase.h" #include "DatabasesTableModel.h" #include "RolesTableModel.h" -#include "PgsqlDatabaseCatalogue.h" +#include "PgDatabaseCatalogue.h" ServerWindow::ServerWindow(MasterController *master, QWidget *parent) : ASyncWindow(parent) diff --git a/src/ServerWindow.h b/src/pglab/ServerWindow.h similarity index 100% rename from src/ServerWindow.h rename to src/pglab/ServerWindow.h diff --git a/src/ServerWindow.ui b/src/pglab/ServerWindow.ui similarity index 100% rename from src/ServerWindow.ui rename to src/pglab/ServerWindow.ui diff --git a/src/SqlSyntaxHighlighter.cpp b/src/pglab/SqlSyntaxHighlighter.cpp similarity index 97% rename from src/SqlSyntaxHighlighter.cpp rename to src/pglab/SqlSyntaxHighlighter.cpp index 92961ee..451ce45 100644 --- a/src/SqlSyntaxHighlighter.cpp +++ b/src/pglab/SqlSyntaxHighlighter.cpp @@ -1,6 +1,6 @@ #include "SqlSyntaxHighlighter.h" -#include "pgtypecontainer.h" +#include "PgTypeContainer.h" #include "SqlLexer.h" namespace { @@ -117,6 +117,9 @@ SqlSyntaxHighlighter::SqlSyntaxHighlighter(QTextDocument *parent) m_typeFormat.setForeground(QColor(32, 192, 32)); m_typeFormat.setFontWeight(QFont::Bold); + + m_parameterFormat.setForeground(QColor(192, 32, 32)); + m_parameterFormat.setFontWeight(QFont::Bold); } SqlSyntaxHighlighter::~SqlSyntaxHighlighter() @@ -144,7 +147,7 @@ void SqlSyntaxHighlighter::highlightBlock(const QString &text) switch (tokentype) { case BasicTokenType::None: case BasicTokenType::End: // End of input - case BasicTokenType::DollarQuotedString: + case BasicTokenType::DollarQuote: break; case BasicTokenType::Symbol: // can be many things, keyword, object name, operator, .. if (g_Keywords.count(s.toLower()) > 0) { @@ -166,6 +169,9 @@ void SqlSyntaxHighlighter::highlightBlock(const QString &text) case BasicTokenType::QuotedIdentifier: setFormat(startpos, length, m_quotedIdentifierFormat); break; + case BasicTokenType::Parameter: + setFormat(startpos, length, m_parameterFormat); + break; } } } diff --git a/src/SqlSyntaxHighlighter.h b/src/pglab/SqlSyntaxHighlighter.h similarity index 95% rename from src/SqlSyntaxHighlighter.h rename to src/pglab/SqlSyntaxHighlighter.h index 877a8b8..e75fd2a 100644 --- a/src/SqlSyntaxHighlighter.h +++ b/src/pglab/SqlSyntaxHighlighter.h @@ -28,6 +28,7 @@ private: QTextCharFormat m_quotedStringFormat; QTextCharFormat m_typeFormat; QTextCharFormat m_quotedIdentifierFormat; + QTextCharFormat m_parameterFormat; t_SymbolSet m_typeNames; }; diff --git a/src/typeselectionitemmodel.cpp b/src/pglab/TypeSelectionItemModel.cpp similarity index 94% rename from src/typeselectionitemmodel.cpp rename to src/pglab/TypeSelectionItemModel.cpp index ed6e930..859058f 100644 --- a/src/typeselectionitemmodel.cpp +++ b/src/pglab/TypeSelectionItemModel.cpp @@ -1,4 +1,4 @@ -#include "typeselectionitemmodel.h" +#include "TypeSelectionItemModel.h" #include "PgTypeContainer.h" #include @@ -61,8 +61,8 @@ void TypeSelectionItemModel::setTypeList(const PgTypeContainer* types) beginResetModel(); m_types.clear(); for (const auto &e : *types) { - if (e.typcategory != 'A' - && e.typtype != 'c') { + if (e.typcategory != "A" + && e.typtype != "c") { m_types.push_back(e.typname); } } diff --git a/src/typeselectionitemmodel.h b/src/pglab/TypeSelectionItemModel.h similarity index 100% rename from src/typeselectionitemmodel.h rename to src/pglab/TypeSelectionItemModel.h diff --git a/src/icons/16x16/document_green.png b/src/pglab/icons/16x16/document_green.png similarity index 100% rename from src/icons/16x16/document_green.png rename to src/pglab/icons/16x16/document_green.png diff --git a/src/icons/16x16/document_red.png b/src/pglab/icons/16x16/document_red.png similarity index 100% rename from src/icons/16x16/document_red.png rename to src/pglab/icons/16x16/document_red.png diff --git a/src/icons/16x16/document_yellow.png b/src/pglab/icons/16x16/document_yellow.png similarity index 100% rename from src/icons/16x16/document_yellow.png rename to src/pglab/icons/16x16/document_yellow.png diff --git a/src/pglab/icons/about.png b/src/pglab/icons/about.png new file mode 100644 index 0000000..1a02d2b Binary files /dev/null and b/src/pglab/icons/about.png differ diff --git a/src/pglab/icons/add_connection.png b/src/pglab/icons/add_connection.png new file mode 100644 index 0000000..8ff7512 Binary files /dev/null and b/src/pglab/icons/add_connection.png differ diff --git a/src/pglab/icons/backup_database.png b/src/pglab/icons/backup_database.png new file mode 100644 index 0000000..64e9423 Binary files /dev/null and b/src/pglab/icons/backup_database.png differ diff --git a/src/pglab/icons/delete_connection.png b/src/pglab/icons/delete_connection.png new file mode 100644 index 0000000..5563984 Binary files /dev/null and b/src/pglab/icons/delete_connection.png differ diff --git a/src/icons/desktop.ini b/src/pglab/icons/desktop.ini similarity index 100% rename from src/icons/desktop.ini rename to src/pglab/icons/desktop.ini diff --git a/src/icons/folder.png b/src/pglab/icons/folder.png similarity index 100% rename from src/icons/folder.png rename to src/pglab/icons/folder.png diff --git a/src/icons/lightbulb.png b/src/pglab/icons/lightbulb.png similarity index 100% rename from src/icons/lightbulb.png rename to src/pglab/icons/lightbulb.png diff --git a/src/icons/lightbulb_off.png b/src/pglab/icons/lightbulb_off.png similarity index 100% rename from src/icons/lightbulb_off.png rename to src/pglab/icons/lightbulb_off.png diff --git a/src/pglab/icons/manage_server.png b/src/pglab/icons/manage_server.png new file mode 100644 index 0000000..7331756 Binary files /dev/null and b/src/pglab/icons/manage_server.png differ diff --git a/src/pglab/icons/new_query_tab.png b/src/pglab/icons/new_query_tab.png new file mode 100644 index 0000000..40f546e Binary files /dev/null and b/src/pglab/icons/new_query_tab.png differ diff --git a/src/pglab/icons/open_query_window.png b/src/pglab/icons/open_query_window.png new file mode 100644 index 0000000..46cd65a Binary files /dev/null and b/src/pglab/icons/open_query_window.png differ diff --git a/src/icons/page_white_add.png b/src/pglab/icons/page_white_add.png similarity index 100% rename from src/icons/page_white_add.png rename to src/pglab/icons/page_white_add.png diff --git a/src/icons/page_white_copy.png b/src/pglab/icons/page_white_copy.png similarity index 100% rename from src/icons/page_white_copy.png rename to src/pglab/icons/page_white_copy.png diff --git a/src/icons/page_white_delete.png b/src/pglab/icons/page_white_delete.png similarity index 100% rename from src/icons/page_white_delete.png rename to src/pglab/icons/page_white_delete.png diff --git a/src/icons/script_delete.png b/src/pglab/icons/script_delete.png similarity index 100% rename from src/icons/script_delete.png rename to src/pglab/icons/script_delete.png diff --git a/src/icons/script_go.png b/src/pglab/icons/script_go.png similarity index 100% rename from src/icons/script_go.png rename to src/pglab/icons/script_go.png diff --git a/src/icons/script_save.png b/src/pglab/icons/script_save.png similarity index 100% rename from src/icons/script_save.png rename to src/pglab/icons/script_save.png diff --git a/src/icons/server_delete.png b/src/pglab/icons/server_delete.png similarity index 100% rename from src/icons/server_delete.png rename to src/pglab/icons/server_delete.png diff --git a/src/icons/server_edit.png b/src/pglab/icons/server_edit.png similarity index 100% rename from src/icons/server_edit.png rename to src/pglab/icons/server_edit.png diff --git a/src/icons/server_go.png b/src/pglab/icons/server_go.png similarity index 100% rename from src/icons/server_go.png rename to src/pglab/icons/server_go.png diff --git a/src/icons/table_save.png b/src/pglab/icons/table_save.png similarity index 100% rename from src/icons/table_save.png rename to src/pglab/icons/table_save.png diff --git a/src/icons/token_shortland_character.png b/src/pglab/icons/token_shortland_character.png similarity index 100% rename from src/icons/token_shortland_character.png rename to src/pglab/icons/token_shortland_character.png diff --git a/src/json/json-forwards.h b/src/pglab/json/json-forwards.h similarity index 100% rename from src/json/json-forwards.h rename to src/pglab/json/json-forwards.h diff --git a/src/json/json.h b/src/pglab/json/json.h similarity index 100% rename from src/json/json.h rename to src/pglab/json/json.h diff --git a/src/jsoncpp.cpp b/src/pglab/jsoncpp.cpp similarity index 100% rename from src/jsoncpp.cpp rename to src/pglab/jsoncpp.cpp diff --git a/src/main.cpp b/src/pglab/main.cpp similarity index 51% rename from src/main.cpp rename to src/pglab/main.cpp index e7d0552..38482a6 100644 --- a/src/main.cpp +++ b/src/pglab/main.cpp @@ -1,12 +1,16 @@ #include "MasterController.h" #include -#include +#ifdef _WIN32 +# include +#endif #include +#include "GlobalIoService.h" int main(int argc, char *argv[]) { /* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */ +#ifdef WIN32 WORD wVersionRequested = MAKEWORD(2, 2); WSADATA wsaData; int err = WSAStartup(wVersionRequested, &wsaData); @@ -16,6 +20,8 @@ int main(int argc, char *argv[]) printf("WSAStartup failed with error: %d\n", err); return 1; } +#endif + QApplication a(argc, argv); @@ -23,11 +29,22 @@ int main(int argc, char *argv[]) QCoreApplication::setOrganizationDomain("eelkeklein.nl"); QCoreApplication::setApplicationName("pglab"); - auto master_controller = std::make_unique(); - master_controller->init(); - int result = a.exec(); + std::thread asio_service_thread; + int result = -1; + { + auto ios = getGlobalAsioIoService(); + boost::asio::io_service::work work(*ios); // Prevent service from running out of work so run doesn't return + asio_service_thread = std::thread([ios](){ ios->run(); }); + + // make sure the io_service is stopped before we wait on the future + auto master_controller = std::make_unique(); + master_controller->init(); + result = a.exec(); + } + asio_service_thread.join(); +#ifdef WIN32 WSACleanup(); - +#endif return result; } diff --git a/src/pglab.ico b/src/pglab/pglab.ico similarity index 100% rename from src/pglab.ico rename to src/pglab/pglab.ico diff --git a/src/resources.qrc b/src/pglab/resources.qrc similarity index 72% rename from src/resources.qrc rename to src/pglab/resources.qrc index 657d688..8b00d1b 100644 --- a/src/resources.qrc +++ b/src/pglab/resources.qrc @@ -1,6 +1,5 @@  - icons/server_add.png icons/server_delete.png icons/server_go.png icons/script_delete.png @@ -12,13 +11,18 @@ icons/page_white_add.png icons/page_white_delete.png icons/lightbulb_off.png - icons/information.png icons/16x16/document_green.png icons/16x16/document_red.png icons/16x16/document_yellow.png - icons/backups.png icons/page_white_copy.png icons/token_shortland_character.png icons/server_edit.png + icons/new_query_tab.png + icons/about.png + icons/backup_database.png + icons/add_connection.png + icons/delete_connection.png + icons/open_query_window.png + icons/manage_server.png diff --git a/src/src.pro b/src/pglab/src.pro similarity index 100% rename from src/src.pro rename to src/pglab/src.pro diff --git a/src/stopwatch.cpp b/src/pglab/stopwatch.cpp similarity index 100% rename from src/stopwatch.cpp rename to src/pglab/stopwatch.cpp diff --git a/src/stopwatch.h b/src/pglab/stopwatch.h similarity index 100% rename from src/stopwatch.h rename to src/pglab/stopwatch.h diff --git a/src/tsqueue.cpp b/src/pglab/tsqueue.cpp similarity index 70% rename from src/tsqueue.cpp rename to src/pglab/tsqueue.cpp index 9200692..b49b6a0 100644 --- a/src/tsqueue.cpp +++ b/src/pglab/tsqueue.cpp @@ -1,14 +1,14 @@ #include "tsqueue.h" TSQueue::TSQueue() - : newData(Win32Event::Reset::Manual, Win32Event::Initial::Clear) +// : newData(Win32Event::Reset::Manual, Win32Event::Initial::Clear) {} void TSQueue::add(t_Callable callable) { std::lock_guard g(m); futureQueue.push_back(std::move(callable)); - newData.set(); +// newData.set(); } bool TSQueue::empty() @@ -23,12 +23,12 @@ TSQueue::t_Callable TSQueue::pop() auto f = std::move(futureQueue.front()); futureQueue.pop_front(); if (futureQueue.empty()) { - newData.reset(); +// newData.reset(); } return f; } -HANDLE TSQueue::getNewDataEventHandle() -{ - return newData.handle(); -} +// HANDLE TSQueue::getNewDataEventHandle() +// { +// return newData.handle(); +// } diff --git a/src/tsqueue.h b/src/pglab/tsqueue.h similarity index 71% rename from src/tsqueue.h rename to src/pglab/tsqueue.h index acb7934..12a915e 100644 --- a/src/tsqueue.h +++ b/src/pglab/tsqueue.h @@ -1,7 +1,7 @@ #ifndef TSQUEUE_H #define TSQUEUE_H -#include "Win32Event.h" +//#include "Win32Event.h" #include #include #include @@ -15,11 +15,11 @@ public: bool empty(); t_Callable pop(); - HANDLE getNewDataEventHandle(); + //HANDLE getNewDataEventHandle(); Looks like this wasn't use at all so we can leave the event out. private: using t_CallableQueue = std::deque; - Win32Event newData; + //Win32Event newData; std::mutex m; t_CallableQueue futureQueue; }; diff --git a/src/tuplesresultwidget.cpp b/src/pglab/tuplesresultwidget.cpp similarity index 100% rename from src/tuplesresultwidget.cpp rename to src/pglab/tuplesresultwidget.cpp diff --git a/src/tuplesresultwidget.h b/src/pglab/tuplesresultwidget.h similarity index 94% rename from src/tuplesresultwidget.h rename to src/pglab/tuplesresultwidget.h index e1414af..7511404 100644 --- a/src/tuplesresultwidget.h +++ b/src/pglab/tuplesresultwidget.h @@ -1,7 +1,7 @@ #ifndef TUPLESRESULTWIDGET_H #define TUPLESRESULTWIDGET_H -#include "queryresultmodel.h" +#include "QueryResultModel.h" #include namespace Ui { diff --git a/src/tuplesresultwidget.ui b/src/pglab/tuplesresultwidget.ui similarity index 100% rename from src/tuplesresultwidget.ui rename to src/pglab/tuplesresultwidget.ui diff --git a/src/util.cpp b/src/pglab/util.cpp similarity index 96% rename from src/util.cpp rename to src/pglab/util.cpp index 749c7cc..ae4bb71 100644 --- a/src/util.cpp +++ b/src/pglab/util.cpp @@ -1,5 +1,5 @@ #include "util.h" -#include "csvwriter.h" +#include "CsvWriter.h" #include #include #include @@ -108,8 +108,7 @@ void copySelectionToClipboard(const QTableView *view) QString ConvertToMultiLineCString(const QString &in) { - // We need to atleast escape " and \ - // also any multi byte utf8 char + // We need to atleast escape " and \ and also any multi byte utf8 char QString out; out.append('"'); diff --git a/src/util.h b/src/pglab/util.h similarity index 100% rename from src/util.h rename to src/pglab/util.h diff --git a/src/pgsql/CMakeLists.txt b/src/pgsql/CMakeLists.txt new file mode 100644 index 0000000..bc6c34f --- /dev/null +++ b/src/pgsql/CMakeLists.txt @@ -0,0 +1,22 @@ + +add_library(pgsql STATIC + Pgsql_Connection.cpp + Pgsql_Params.cpp + Pgsql_Result.cpp + Pgsql_Row.cpp + Pgsql_Value.cpp) + +target_link_libraries(pgsql PUBLIC + postgresql + Qt5::Core + ) + +target_include_directories(pgsql INTERFACE + $ +) + +set_target_properties(pgsql PROPERTIES + CXX_STANDARD 14 + CXX_STANDARD_REQUIRED ON + POSITION_INDEPENDENT_CODE True + ) diff --git a/src/PgsqlConn.cpp b/src/pgsql/Pgsql_Connection.cpp similarity index 99% rename from src/PgsqlConn.cpp rename to src/pgsql/Pgsql_Connection.cpp index 78b37d5..9555434 100644 --- a/src/PgsqlConn.cpp +++ b/src/pgsql/Pgsql_Connection.cpp @@ -1,4 +1,4 @@ -#include "PgsqlConn.h" +#include "Pgsql_Connection.h" #include "Pgsql_declare.h" #include "Pgsql_Params.h" #include diff --git a/src/PgsqlConn.h b/src/pgsql/Pgsql_Connection.h similarity index 99% rename from src/PgsqlConn.h rename to src/pgsql/Pgsql_Connection.h index 80654c7..74dbf1c 100644 --- a/src/PgsqlConn.h +++ b/src/pgsql/Pgsql_Connection.h @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include diff --git a/src/Pgsql_Params.cpp b/src/pgsql/Pgsql_Params.cpp similarity index 100% rename from src/Pgsql_Params.cpp rename to src/pgsql/Pgsql_Params.cpp diff --git a/src/Pgsql_Params.h b/src/pgsql/Pgsql_Params.h similarity index 98% rename from src/Pgsql_Params.h rename to src/pgsql/Pgsql_Params.h index 7e10e88..a9e9950 100644 --- a/src/Pgsql_Params.h +++ b/src/pgsql/Pgsql_Params.h @@ -3,7 +3,7 @@ #include #include -#include +#include #include "Pgsql_declare.h" namespace Pgsql { diff --git a/src/Pgsql_Result.cpp b/src/pgsql/Pgsql_Result.cpp similarity index 100% rename from src/Pgsql_Result.cpp rename to src/pgsql/Pgsql_Result.cpp diff --git a/src/Pgsql_Result.h b/src/pgsql/Pgsql_Result.h similarity index 99% rename from src/Pgsql_Result.h rename to src/pgsql/Pgsql_Result.h index fdcd54a..471ad38 100644 --- a/src/Pgsql_Result.h +++ b/src/pgsql/Pgsql_Result.h @@ -132,4 +132,5 @@ namespace Pgsql { } // end namespace Pgsql + #endif // PGSQL_RESULT_H diff --git a/src/Pgsql_Row.cpp b/src/pgsql/Pgsql_Row.cpp similarity index 100% rename from src/Pgsql_Row.cpp rename to src/pgsql/Pgsql_Row.cpp diff --git a/src/Pgsql_Row.h b/src/pgsql/Pgsql_Row.h similarity index 100% rename from src/Pgsql_Row.h rename to src/pgsql/Pgsql_Row.h diff --git a/src/Pgsql_Value.cpp b/src/pgsql/Pgsql_Value.cpp similarity index 97% rename from src/Pgsql_Value.cpp rename to src/pgsql/Pgsql_Value.cpp index 731b2e8..e4095cb 100644 --- a/src/Pgsql_Value.cpp +++ b/src/pgsql/Pgsql_Value.cpp @@ -44,7 +44,7 @@ Value::operator Oid() const return operator int(); } -Value::operator __int64() const +Value::operator long long() const { return std::strtoull(m_val, nullptr, 10); } diff --git a/src/Pgsql_Value.h b/src/pgsql/Pgsql_Value.h similarity index 97% rename from src/Pgsql_Value.h rename to src/pgsql/Pgsql_Value.h index 2eec654..8b07046 100644 --- a/src/Pgsql_Value.h +++ b/src/pgsql/Pgsql_Value.h @@ -21,7 +21,7 @@ namespace Pgsql { operator short() const; operator int() const; operator Oid() const; - operator __int64() const; + operator long long() const; operator bool() const; private: const char *m_val; @@ -41,7 +41,8 @@ namespace Pgsql { { s = static_cast(v); } - + + } // end namespace Pgsql #endif // PGSQL_VALUE_H diff --git a/src/Pgsql_declare.h b/src/pgsql/Pgsql_declare.h similarity index 94% rename from src/Pgsql_declare.h rename to src/pgsql/Pgsql_declare.h index 9454641..279d09b 100644 --- a/src/Pgsql_declare.h +++ b/src/pgsql/Pgsql_declare.h @@ -1,7 +1,7 @@ #ifndef PGSQL_DECLARE_H #define PGSQL_DECLARE_H -#include +#include namespace Pgsql { diff --git a/src/sqlhighlighter.cpp b/src/sqlhighlighter.cpp deleted file mode 100644 index d503f16..0000000 --- a/src/sqlhighlighter.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include "SqlHighlighter.h" - -static const wchar_t *keywords[] = { - L"as", L"alter", L"all", L"and", L"any", L"by", L"char", L"column", L"create", L"database", L"date", L"from", L"full", L"group", L"having", - L"in", L"inner", L"int", L"join", L"left", L"not", L"numeric", L"or", L"order", L"outer", L"right", L"select", L"smallint", L"table", L"time", - L"timestamp", L"timestamptz", L"varchar", L"where" -}; - -static const wchar_t *operators[] = { - L"+", L"-", L"*", L"/", L"<", L">", L"<=", L">=", L"<>", L"!=", L"~" -}; - - -/* - - + - * / < > = ~ ! @ # % ^ & | ` ? - -There are a few restrictions on your choice of name: - - -- and /* cannot appear anywhere in an operator name, since they will be taken as the start of a comment. - - A multicharacter operator name cannot end in + or -, unless the name also contains at least one of these characters: - - ~ ! @ # % ^ & | ` ? - For example, @- is an allowed operator name, but *- is not. This restriction allows PostgreSQL to parse SQL-compliant commands without requiring spaces between tokens. - - The use of => as an operator name is deprecated. It may be disallowed altogether in a future release. - -The operator != is mapped to <> on input, so these two names are always equivalent. - -+ - * / < > = - -*/ - -//static auto types = R"-(bigint|boolean|char|character varying|date|int[248]|integer|numeric|smallint|time|timestamp(?:tz)?|timestamp(?:\s+with\s+timezone)?|varchar)-"; -//static auto err = R"-(left|right|inner|outer)-"; - -// static_assert(sizeof(keywords)/4 == 25, -// "sizeof keywords"); - - -SqlHighlighter::SqlHighlighter(QTextDocument *parent) - : QSyntaxHighlighter(parent) -{ -// { - static auto keywords = - R"-(\balter\b|\ball\b|\band\b|\bany\b|\bas\b|\bby\b|\bcascade\b|\bcheck\b|\bcolumn\b|\bcopy\b|\bcreate\b|\bdatabase\b|\bdefault\b|\bdelete\b)-" - R"-(|\foreign\b|\bfrom\b|\bgroup\b|\bhaving\b|\bin\b|\bindex\b|\bis\b|\bkey\b|\blimit\b|\bnatural\b|\bnot\b|\bnull\b|\boffset\b|\bon\b)-" - R"-(|\bor\b|\border\b|\bover\b|\bparition\b|\bprimary\b|\breferences\b|\brestrict\b|\bselect\b|\btable\b|\btruncate\b|\bunique\b|\bupdate\b|\busing\b)-" - R"-(|\bwhere\b|\bwith\b|(?:(?:inner|(?:left|right|full)(\s+outer)?)\s+)?join)-"; - - // into temp DISTINCT true false - - static auto types = - R"-(\bbigint\b|\bboolean\b|\bchar\b|\bcharacter varying\b|\bdate\b|\bint[248]\b|\binteger\b|\bnumeric\b|\bsmallint\b)-" - R"-(|\btime\b|\btimestamp(?:tz)?\b|\btimestamp(?:\s+with\s+time\s+zone)?\b|\bvarchar\b)-"; -// static auto err = R"-(left|right|inner|outer)-"; - -// QTextCharFormat errFormat; -// errFormat.setForeground(QColor(255, 128, 128)); -// errFormat.setFontWeight(QFont::Bold); -// highlightingRules.emplace_back(QRegExp(err, Qt::CaseInsensitive), errFormat); - - QTextCharFormat keywordFormat; - keywordFormat.setForeground(QColor(64, 64, 192)); - keywordFormat.setFontWeight(QFont::Bold); - highlightingRules.emplace_back(QRegExp(keywords, Qt::CaseInsensitive), keywordFormat); - - QTextCharFormat typesFormat; - typesFormat.setForeground(QColor(64, 192, 64)); - typesFormat.setFontWeight(QFont::Bold); - highlightingRules.emplace_back(QRegExp(types, Qt::CaseInsensitive), typesFormat); - -// } -} - -void SqlHighlighter::highlightBlock(const QString &text) -{ - foreach (const HighlightingRule &rule, highlightingRules) { - QRegExp expression(rule.pattern); - int index = expression.indexIn(text); - while (index >= 0) { - int length = expression.matchedLength(); - setFormat(index, length, rule.format); - index = expression.indexIn(text, index + length); - } - } - setCurrentBlockState(0); -} - - - diff --git a/src/sqlhighlighter.h b/src/sqlhighlighter.h deleted file mode 100644 index ee3ab91..0000000 --- a/src/sqlhighlighter.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include -#include - -#include - -class SqlHighlighter : public QSyntaxHighlighter -{ - Q_OBJECT - -public: - SqlHighlighter(QTextDocument *parent = 0); - -protected: - void highlightBlock(const QString &text) override; - -private: - struct HighlightingRule - { - QRegExp pattern; - QTextCharFormat format; - - HighlightingRule(const QRegExp ®ex, const QTextCharFormat &f) - : pattern(regex), format(f) - {} - }; - //QVector highlightingRules; - std::vector highlightingRules; - -// QRegExp commentStartExpression; - // QRegExp commentEndExpression; - - QTextCharFormat keywordFormat; -// QTextCharFormat classFormat; -// QTextCharFormat singleLineCommentFormat; -// QTextCharFormat multiLineCommentFormat; -// QTextCharFormat quotationFormat; -// QTextCharFormat functionFormat; - -}; - diff --git a/src/sqlparser.cpp b/src/sqlparser.cpp deleted file mode 100644 index 3d960b0..0000000 --- a/src/sqlparser.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "sqlparser.h" - -/** Responsible for splitting the query into logical elements. - * - * It first uses common seperators to split the input, then it tries - * to determine if the fields it gets have a special meaning. - * - * However because SQL is very forgiving about the use of keywords - * as names. - * - * The lexical analyzer does however distinguish between - * - symbols/keywords (symbols might be schema, table, columns, functions etc) - * - numbers - * - strings - * - quoted symbol (a symbol between "" must be the name of something) - * - * seperators - * whitespace - * special chars ;,. - * operators - */ -class LexicalAnalyser { -public: - -}; - -SqlParser::SqlParser() -{ - -} diff --git a/src/sqlparser.h b/src/sqlparser.h deleted file mode 100644 index 4dc8b4d..0000000 --- a/src/sqlparser.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef SQLPARSER_H -#define SQLPARSER_H - - -class SqlParser -{ -public: - SqlParser(); -}; - -#endif // SQLPARSER_H \ No newline at end of file diff --git a/src/waithandlelist.cpp b/src/waithandlelist.cpp deleted file mode 100644 index e05bba4..0000000 --- a/src/waithandlelist.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "waithandlelist.h" -#include "win32event.h" - -WaitHandleList::WaitHandleList() = default; -WaitHandleList::~WaitHandleList() = default; - -WaitResultValue WaitHandleList::add(HANDLE h) -{ - m_waitHandles.push_back(h); - return WAIT_OBJECT_0 + static_cast(m_waitHandles.size() - 1); -} - -WaitResultValue WaitHandleList::add(Win32Event &e) -{ - return add(e.handle()); -} - -DWORD WaitHandleList::count() const -{ - return static_cast(m_waitHandles.size()); -} - -void WaitHandleList::clear() -{ - m_waitHandles.clear(); -} - -WaitHandleList::operator const HANDLE*() const -{ - return m_waitHandles.data(); -} diff --git a/src/waithandlelist.h b/src/waithandlelist.h deleted file mode 100644 index 376e817..0000000 --- a/src/waithandlelist.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef WAITHANDLELIST_H -#define WAITHANDLELIST_H - -#include -#include - -class Win32Event; - -using WaitResultValue = DWORD; - -class WaitHandleList { -public: - WaitHandleList(); - ~WaitHandleList(); - - WaitResultValue add(HANDLE h); - WaitResultValue add(Win32Event &e); - DWORD count() const; - void clear(); - operator const HANDLE*() const; - -private: - std::vector m_waitHandles; -}; - -#endif // WAITHANDLELIST_H diff --git a/src/win32event.cpp b/src/win32event.cpp deleted file mode 100644 index 3c3625d..0000000 --- a/src/win32event.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "win32event.h" diff --git a/src/win32event.h b/src/win32event.h deleted file mode 100644 index 684d13f..0000000 --- a/src/win32event.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef WIN32EVENT_H -#define WIN32EVENT_H - -#include - -#include -/** Simpel wrapper around a Win32 Event object. - -Mostly to make cleanup automatic.*/ -class Win32Event { -public: - enum class Reset { Auto=0, Manual=1 }; - enum class Initial { Clear=0, Set=1 }; - - Win32Event(Reset r, Initial is) - : hEvent(CreateEvent( - nullptr, // _In_opt_ LPSECURITY_ATTRIBUTES lpEventAttributes, - BOOL(r), // _In_ BOOL bManualReset, - BOOL(is), // _In_ BOOL bInitialState, - nullptr //_In_opt_ LPCTSTR lpName - )) - {} - - Win32Event(Reset r, Initial is, int sock, long net_events) - : Win32Event(r, is) - { - WSAEventSelect(sock, hEvent, net_events); - } - - ~Win32Event() - { - CloseHandle(hEvent); - } - - Win32Event(const Win32Event &) = delete; - Win32Event &operator=(const Win32Event &) = delete; - - void set() { SetEvent(hEvent); } - - void reset() { ResetEvent(hEvent); } - - HANDLE handle() { return hEvent; } -private: - HANDLE hEvent; -}; - -#endif // WIN32EVENT_H diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro deleted file mode 100644 index 576a9ff..0000000 --- a/tests/auto/auto.pro +++ /dev/null @@ -1,3 +0,0 @@ -TEMPLATE = subdirs - -SUBDIRS += mycase diff --git a/tests/auto/gtest_dependency.pri b/tests/auto/gtest_dependency.pri deleted file mode 100644 index d01d7f0..0000000 --- a/tests/auto/gtest_dependency.pri +++ /dev/null @@ -1,29 +0,0 @@ -isEmpty(GOOGLETEST_DIR):GOOGLETEST_DIR=$$(GOOGLETEST_DIR) - -isEmpty(GOOGLETEST_DIR) { - warning("Using googletest src dir specified at Qt Creator wizard") - message("set GOOGLETEST_DIR as environment variable or qmake variable to get rid of this message") - GOOGLETEST_DIR = C:/Prog/googletest -} - -!isEmpty(GOOGLETEST_DIR): { - GTEST_SRCDIR = $$GOOGLETEST_DIR/googletest - GMOCK_SRCDIR = $$GOOGLETEST_DIR/googlemock -} - -requires(exists($$GTEST_SRCDIR):exists($$GMOCK_SRCDIR)) - -!exists($$GOOGLETEST_DIR):message("No googletest src dir found - set GOOGLETEST_DIR to enable.") - -DEFINES += \ - GTEST_LANG_CXX11 - -INCLUDEPATH *= \ - $$GTEST_SRCDIR \ - $$GTEST_SRCDIR/include \ - $$GMOCK_SRCDIR \ - $$GMOCK_SRCDIR/include - -SOURCES += \ - $$GTEST_SRCDIR/src/gtest-all.cc \ - $$GMOCK_SRCDIR/src/gmock-all.cc diff --git a/tests/auto/mycase/main.cpp b/tests/auto/mycase/main.cpp deleted file mode 100644 index 046652f..0000000 --- a/tests/auto/mycase/main.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "tst_CsvWriter.h" -#include "tst_expected.h" -#include "tst_PasswordManager.h" -#include "tst_scopeguard.h" -#include "tst_SqlLexer.h" - -#include - -int main(int argc, char *argv[]) -{ - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/tests/auto/mycase/mycase.pro b/tests/auto/mycase/mycase.pro deleted file mode 100644 index 8572e21..0000000 --- a/tests/auto/mycase/mycase.pro +++ /dev/null @@ -1,31 +0,0 @@ -include(../gtest_dependency.pri) - -TEMPLATE = app -CONFIG += console c++11 -CONFIG -= app_bundle -CONFIG += thread -CONFIG += qt - -QT += core - -HEADERS += \ - tst_expected.h \ - tst_SqlLexer.h \ - tst_scopeguard.h \ - tst_CsvWriter.h \ - tst_PasswordManager.h - -SOURCES += main.cpp - -win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../../../core/release/ -lcore -else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../../../core/debug/ -lcore - -INCLUDEPATH += C:\prog\include C:\VSproj\boost_1_63_0 -INCLUDEPATH += $$PWD/../../../core -DEPENDPATH += $$PWD/../../../core -LIBS += c:\prog\lib\botand_imp.lib - -win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../../core/release/libcore.a -else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../../core/debug/libcore.a -else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../../core/release/core.lib -else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../../core/debug/core.lib diff --git a/tests/auto/mycase/tst_SqlLexer.h b/tests/auto/mycase/tst_SqlLexer.h deleted file mode 100644 index 25d6535..0000000 --- a/tests/auto/mycase/tst_SqlLexer.h +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include -#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_THAT(startpos, Eq(1)); - ASSERT_THAT(length, Eq(6)); - ASSERT_THAT(tokentype, Eq(BasicTokenType::Symbol)); - ASSERT_THAT( out, Eq(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_THAT(startpos, Eq(1)); - ASSERT_THAT(length, Eq(10)); - ASSERT_THAT(tokentype, Eq(BasicTokenType::QuotedString)); -} - diff --git a/tests/tests.pro b/tests/tests.pro deleted file mode 100644 index f927700..0000000 --- a/tests/tests.pro +++ /dev/null @@ -1,3 +0,0 @@ -TEMPLATE = subdirs - -SUBDIRS += auto