diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..30cf57e --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,10 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Ignored default folder with query files +/queries/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/editor.xml b/.idea/editor.xml new file mode 100644 index 0000000..a3aeb4c --- /dev/null +++ b/.idea/editor.xml @@ -0,0 +1,367 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..498ae80 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/pgLab.iml b/.idea/pgLab.iml new file mode 100644 index 0000000..6102194 --- /dev/null +++ b/.idea/pgLab.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.junie/skills/reno-release-notes/SKILL.md b/.junie/skills/reno-release-notes/SKILL.md new file mode 100644 index 0000000..2a1779f --- /dev/null +++ b/.junie/skills/reno-release-notes/SKILL.md @@ -0,0 +1,110 @@ +--- +name: reno-release-notes +description: Create, review and lint pgLab release notes with reno (releasenotes/notes YAML fragments). Use whenever the user mentions reno, release notes, releasenotes/notes, "reno new", "reno lint", or asks to add or check a note for a user-visible change in pgLab, even if reno is not named explicitly. +--- + +# reno release notes in pgLab + +pgLab uses [reno](https://docs.openstack.org/reno/latest/) for release notes. +Each user-visible change adds its own small YAML file in `releasenotes/notes/`, +committed together with the change. reno derives the release from git tags, so +never move or rename notes to change releases. Content is reStructuredText, not +Markdown. + +The notes are rendered in the Sphinx user docs through the +`.. release-notes::` directive in `docs/releasenotes.rst` (docs build: +`pip install -r docs/requirements.txt && sphinx-build -b html docs userdocs`). +The About dialog links to the generated `releasenotes.html`. + +## When to write a note + +Write one for: new features, behaviour changes users will notice (UI, menus, +shortcuts, query/code generation output, connection handling), bug fixes, +known issues, and upgrade impact (e.g. changed stored settings or connection +config format). + +Skip: pure refactors, build-system/CI changes, test-only changes, internal +code cleanup, docs-only edits. + +## Sections configured for this project + +Defined in `releasenotes/config.yaml` (render order). Only these keys are valid; +others (`deprecations`, `critical`) are NOT configured here and will not render. + +| Key | Rendered title | Use for | +|------------|------------------|--------------------------------------------| +| `prelude` | (implicit) | Release-wide summary, single string | +| `features` | New Features | New functionality | +| `other` | Changes | Changes to existing behaviour, minor items | +| `issues` | Known Issues | Known problems / limitations | +| `upgrade` | Upgrade Notes | What users must do or know when upgrading | +| `security` | Security Issues | Security fixes | +| `fixes` | Bug Fixes | Ordinary bug fixes | + +Every section except `prelude` is a list of strings. Encoding is utf8. + +## Creating a note + +From the repo root (`pip install reno` if missing): + +```bash +reno new short-descriptive-slug +``` + +This creates `releasenotes/notes/short-descriptive-slug-<16 hex>.yaml`. Keep the +random suffix. Existing examples: `f5-bindings-…`, +`connection-details-in-window-title-…`, `dollar-quoted-string-…`. +Delete all unused template sections, keep only what you need. + +```yaml +--- +features: + - | + The query tool now executes the current statement with + :kbd:`F5`. +fixes: + - | + Fixed reconnect dialog that kept popping up after the connection was lost. +``` + +Short single-line items may be plain (`- text`), longer ones use `- |`. +Wrap at roughly 80 columns. + +## Writing style + +- Write for pgLab users, not patch reviewers: describe the visible effect, not + the implementation (no class or function names unless users see them). +- Past or present tense, full sentences, one bullet per distinct change. +- RST markup: inline literals with double backticks (``` ``pg_catalog`` ```), + links as `` `text `_ ``, GUI menu paths with + `:menuselection:` (e.g. `:menuselection:`Help --> About``), keys with + `:kbd:`. No Markdown, no single-backtick code. +- Mention the PostgreSQL feature or object type involved when relevant. +- For `upgrade`, state the action required. + +## Validate before committing + +```bash +reno lint +reno list # note must be tracked by git to appear for tagged history +``` + +Common failures: YAML indentation/tabs, misspelled section key, a string where +a list is required (or a list for `prelude`), an unconfigured section, bad RST. +Optionally build the docs (command above) to check rendering. + +## Commit rules + +- `git add releasenotes/notes/` and commit it in the same commit as the + change, not a follow-up. +- Commit messages are plain imperative sentences (e.g. "Fix reconnect dialog + popping up repeatedly."). +- To correct a note, edit the same file; don't add a second one. + +## Troubleshooting + +- Note missing in report: not committed, or shallow clone without tags + (`git fetch --tags --unshallow`). +- Wrong release: decided by git history/tags; check `reno list`. +- Broken rendering: almost always RST (single backticks, Markdown links, + indentation). diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..b9c08b0 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,32 @@ +# AGENTS.md + +pgLab: Qt 6 / C++20 desktop GUI for PostgreSQL. + +## Layout (link order: core, pgsql -> pglablib -> pglab) +- `core/` – generic utilities (SQL lexer, CSV writer, `Expected`, JSON); no DB access. +- `pgsql/` – thin C++ wrapper around libpq (connection, result, params, oids). +- `pglablib/` – catalog models, code builders, query generation, connection config. +- `pglab/` – the Qt Widgets application (executable). +- `tests/` – gtest executables `PgsqlTests` and `pglabtests`, plus `mygtestutils` (Qt `PrintTo` helpers). +- `docs/` – Sphinx user docs; `releasenotes/notes` – `reno` notes. + +## Build and test +CMake + vcpkg is the active build system (`VCPKG_ROOT` must be set). Qt 6 is not provided by vcpkg; it must be installed on the system. +``` +cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake +cmake --build build +ctest --test-dir build --output-on-failure +``` +- Run one suite: `./build/tests/pglabtests/pglabtests --gtest_filter='SqlLexer*'` (same for `PgsqlTests`). +- `-DBUILD_TESTS=OFF` skips tests. `build/` is git-ignored; the first configure builds dependencies and is slow. +- Run the app headless with `QT_QPA_PLATFORM=offscreen ./build/pglab/pglab`. It needs a PostgreSQL server for anything useful. + +## Gotchas +- Tests are registered per executable, so each `ctest` entry covers a whole suite. +- A new test file must be added to the `add_executable` list in `tests//CMakeLists.txt`. Sources are listed explicitly, with no globbing. The same goes for new sources in each library's `CMakeLists.txt`. +- `core/test/` is not referenced by any CMake file (its tests are built from `tests/pglabtests`). Don't expect changes there to be compiled. +- `AUTOMOC`/`AUTOUIC`/`AUTORCC` are on globally, so `.ui` and `.qrc` files only need to be listed as sources. +- `BOOST_ENABLE_ASSERT_HANDLER` is defined; the handler lives in `core/my_boost_assert_handler.cpp`. +- Commit messages are plain imperative sentences. User-visible changes need a reno note (`releasenotes/notes`). +- Docs build: `pip install -r docs/requirements.txt && sphinx-build -b html docs userdocs`. +- Windows (VS 2022) is also a supported platform. Avoid Linux-only code, and don't break `WIN32_LEAN_AND_MEAN`/`NOMINMAX` assumptions. diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..a172074 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,30 @@ +cmake_minimum_required(VERSION 3.21) + +project(pgLab LANGUAGES C CXX) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTORCC ON) + +add_compile_definitions(BOOST_ENABLE_ASSERT_HANDLER QT_DEPRECATED_WARNINGS) +if(WIN32) + add_compile_definitions(WIN32_LEAN_AND_MEAN NOMINMAX) +endif() + +find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets Sql Concurrent) + +option(BUILD_TESTS "Build the gtest executables and register them with ctest" ON) + +add_subdirectory(core) +add_subdirectory(pgsql) +add_subdirectory(pglablib) +add_subdirectory(pglab) + +if(BUILD_TESTS) + enable_testing() + add_subdirectory(tests) +endif() diff --git a/README.md b/README.md index bdf5ea0..7c2eb7e 100644 --- a/README.md +++ b/README.md @@ -11,3 +11,41 @@ The release notes use collected from git using [reno](https://docs.openstack.org - googletest - libpq +Boost, Botan, libpq and googletest are provided by vcpkg through the manifest in `vcpkg.json`, so you do not install them manually. + +## Required tools + +- CMake 3.21 or newer +- A C++20 compiler (GCC or Clang on Linux, Visual Studio 2022 on Windows) +- Qt 6 with the Core, Gui, Widgets, Sql and Concurrent components +- vcpkg, with the `VCPKG_ROOT` environment variable pointing to its checkout +- Ninja or make (optional, for faster builds) +- A PostgreSQL server (only needed to run the application against a database) + +## Building + +Configure with the vcpkg toolchain file. The first configure downloads and builds the dependencies, which takes a while: + +``` +cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake +cmake --build build +``` + +To skip the test executables, add `-DBUILD_TESTS=OFF` to the configure command. + +## Running the tests + +From the build directory, run: + +``` +ctest --output-on-failure +``` + +## Running the application + +The executable is built to `build/pglab/pglab`. On a machine without a display, set `QT_QPA_PLATFORM=offscreen`: + +``` +./build/pglab/pglab +``` + diff --git a/common.pri b/common.pri deleted file mode 100644 index dcff145..0000000 --- a/common.pri +++ /dev/null @@ -1,15 +0,0 @@ -! include( ./local.pri ) { -error( "Use local.pri.sample to create your own local.pri" ) -} - -LIBS += -lUser32 -lws2_32 -llibpq - -CONFIG += c++20 - -# 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 -DEFINES += BOOST_ENABLE_ASSERT_HANDLER -DEFINES += WIN32_LEAN_AND_MEAN NOMINMAX _WIN32_WINNT=0x0501 diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 95b09fc..ec63cf3 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -1,41 +1,31 @@ -set(CMAKE_AUTOMOC ON) - add_library(core STATIC - BackupFormatModel.cpp - CsvWriter.cpp my_boost_assert_handler.cpp - PasswordManager.cpp - SqlLexer.cpp) - + SqlLexer.cpp + CsvWriter.cpp + BackupFormatModel.cpp + ExplainTreeModelItem.cpp + jsoncpp.cpp + SqlLexer.h + ScopeGuard.h + CsvWriter.h + BackupFormatModel.h + Expected.h + ExplainTreeModelItem.h + json/json.h + std_utils.h + IntegerRange.h + ) + target_link_libraries(core PUBLIC - boost - botan - Qt5::Core + Qt6::Core ) - -target_include_directories(core INTERFACE + +target_include_directories(core PUBLIC $ -) + ) -set_target_properties(core PROPERTIES - CXX_STANDARD 14 +set_target_properties(core PROPERTIES + CXX_STANDARD 20 CXX_STANDARD_REQUIRED ON - POSITION_INDEPENDENT_CODE True + POSITION_INDEPENDENT_CODE ON ) - -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/core.pro b/core/core.pro deleted file mode 100644 index 0b424f6..0000000 --- a/core/core.pro +++ /dev/null @@ -1,43 +0,0 @@ -#------------------------------------------------- -# -# Project created by QtCreator 2017-02-26T10:51:14 -# -#------------------------------------------------- - -QT -= gui - -TARGET = core -TEMPLATE = lib -CONFIG += staticlib - -! include( ../common.pri ) { -error( "Couldn't find the common.pri file!" ) -} - -# 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 += my_boost_assert_handler.cpp \ - SqlLexer.cpp \ - CsvWriter.cpp \ - BackupFormatModel.cpp \ - ExplainTreeModelItem.cpp \ - jsoncpp.cpp - -HEADERS += \ - SqlLexer.h \ - ScopeGuard.h \ - CsvWriter.h \ - BackupFormatModel.h \ - Expected.h \ - ExplainTreeModelItem.h \ - json/json.h \ - std_utils.h \ - IntegerRange.h - -unix { - target.path = /usr/lib - INSTALLS += target -} diff --git a/local.pri.sample b/local.pri.sample deleted file mode 100644 index 44b8f1e..0000000 --- a/local.pri.sample +++ /dev/null @@ -1,17 +0,0 @@ -# Need paths here to find following library headers -# - botan -# - boost -# - libpq -# ??? -INCLUDEPATH += c:/prog/include -INCLUDEPATH += c:/prog/include/pgsql -INCLUDEPATH += c:/VSproj/boost/include/boost-1_68 - -# Need paths here to find library files for -# - botan -# - boost -# - libpq -# -LIBS += -L\VSproj\boost\lib -L/PROG/LIB - -GOOGLETEST_DIR = c:/prog/googletest diff --git a/pglab/CMakeLists.txt b/pglab/CMakeLists.txt index d6a1072..ab4dda5 100644 --- a/pglab/CMakeLists.txt +++ b/pglab/CMakeLists.txt @@ -1,69 +1,115 @@ -cmake_minimum_required(VERSION 3.2) -project(pglab) +set(PGLAB_SOURCES + main.cpp + About.cpp + catalog/delegates/IconColumnDelegate.cpp + catalog/models/BaseTableModel.cpp + catalog/models/ColumnTableModel.cpp + catalog/models/ConstraintModel.cpp + catalog/models/DatabasesTableModel.cpp + catalog/models/DependantsTableModel.cpp + catalog/models/IndexModel.cpp + catalog/models/ProcTableModel.cpp + catalog/models/RolesTableModel.cpp + catalog/models/SequenceModel.cpp + catalog/models/TriggerTableModel.cpp + catalog/tables/TablesTableModel.cpp + catalog/widgets/CatalogConstraintPage.cpp + catalog/widgets/CatalogFunctionsPage.cpp + catalog/widgets/CatalogIndexPage.cpp + catalog/widgets/CatalogInspector.cpp + catalog/widgets/CatalogNamespacePage.cpp + catalog/widgets/CatalogPageBase.cpp + catalog/widgets/CatalogSequencesPage.cpp + catalog/widgets/CatalogTablesPage.cpp + catalog/widgets/CatalogTypesPage.cpp + catalog/widgets/ColumnPage.cpp + catalog/widgets/DependantsPage.cpp + catalog/widgets/TriggerPage.cpp + codeeditor/CodeEditor.cpp + codeeditor/EditorGutter.cpp + codeeditor/GutterPainter.cpp + crud/CrudModel.cpp + crud/CrudTab.cpp + querytool/QueryExplainModel.cpp + querytool/QueryParamListController.cpp + querytool/QueryResultModel.cpp + querytool/QueryTool.cpp + serverinspector/DatabasesPage.cpp + serverinspector/RolesPage.cpp + serverinspector/ServerInspector.cpp + util/Colors.cpp + util/PgLabItemDelegate.cpp + util/PgLabTableView.cpp + util/SqlSyntaxHighlighter.cpp + ConnectionConfigurationWidget.cpp + ConnectionController.cpp + ManagedPage.cpp + PgDumpOutputHighlighter.cpp + CreateDatabaseDialog.cpp + ConnectionManagerWindow.cpp + ConnectionListModel.cpp + SslModeModel.cpp + stopwatch.cpp + tuplesresultwidget.cpp + BackupDialog.cpp + MasterController.cpp + ParamTypeDelegate.cpp + OpenDatabase.cpp + ProcessStdioWidget.cpp + ResultTableModelUtil.cpp + NamespaceItemModel.cpp + PropertyProxyModel.cpp + CodeGenerator.cpp + UserConfiguration.cpp + widgets/SqlCodePreview.cpp + CustomFilterSortModel.cpp + PropertiesPage.cpp + PasswordPromptDialog.cpp + EditTableWidget.cpp + EditColumnTableModel.cpp + DatabaseWindow.cpp + widgets/SingleRecordModel.cpp + widgets/SingleRecordWidget.cpp + ) -set(CMAKE_AUTOMOC ON) -set(CMAKE_AUTOUIC ON) -set(CMAKE_AUTORCC ON) +set(PGLAB_FORMS + ConnectionManagerWindow.ui + CreateDatabaseDialog.ui + DatabaseWindow.ui + tuplesresultwidget.ui + querytool/QueryTab.ui + ProcessStdioWidget.ui + crud/CrudTab.ui + CodeGenerator.ui + widgets/SingleRecordWidget.ui + ) add_executable(pglab - ASyncDBConnection.cpp - ASyncWindow.cpp - BackupDialog.cpp - BackupRestore.cpp - CodeBuilderConfiguration.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 + ${PGLAB_SOURCES} + ${PGLAB_FORMS} 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") +if(WIN32) + set_target_properties(pglab PROPERTIES WIN32_EXECUTABLE ON) endif() -target_link_libraries( pglab - core +target_link_libraries(pglab PRIVATE + pglablib pgsql - boost-system - Qt5::Widgets - pthread + core + Qt6::Core + Qt6::Gui + Qt6::Widgets + Qt6::Sql + Qt6::Concurrent + ) + +target_include_directories(pglab PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ) + +set_target_properties(pglab PROPERTIES + CXX_STANDARD 20 + CXX_STANDARD_REQUIRED ON ) diff --git a/pglab/CreateDatabaseDialog.h b/pglab/CreateDatabaseDialog.h index bcc00af..74cb209 100644 --- a/pglab/CreateDatabaseDialog.h +++ b/pglab/CreateDatabaseDialog.h @@ -3,7 +3,7 @@ #include -#include "catalog\PgDatabase.h" +#include "catalog/PgDatabase.h" class PgDatabaseCatalog; diff --git a/pglab/CreateDatabaseDialog.ui b/pglab/CreateDatabaseDialog.ui index f17dbac..a16e077 100644 --- a/pglab/CreateDatabaseDialog.ui +++ b/pglab/CreateDatabaseDialog.ui @@ -148,7 +148,7 @@ CodeEditor QPlainTextEdit -
codeeditor\CodeEditor.h
+
codeeditor/CodeEditor.h
diff --git a/pglab/catalog/models/DatabasesTableModel.cpp b/pglab/catalog/models/DatabasesTableModel.cpp index ac10ec5..289eea2 100644 --- a/pglab/catalog/models/DatabasesTableModel.cpp +++ b/pglab/catalog/models/DatabasesTableModel.cpp @@ -169,7 +169,7 @@ QVariant DatabasesTableModel::getData(const QModelIndex &index) const break; case SizeCol: if (d.size.totalBytes >= 0) - v = d.size.totalBytes; + v = QVariant::fromValue(d.size.totalBytes); break; case AclCol: v = db.aclString(); diff --git a/pglab/catalog/models/IndexModel.cpp b/pglab/catalog/models/IndexModel.cpp index 7cee4e4..e04f715 100644 --- a/pglab/catalog/models/IndexModel.cpp +++ b/pglab/catalog/models/IndexModel.cpp @@ -114,7 +114,7 @@ QVariant IndexModel::getData(const QModelIndex &index) const break; case SizeCol: - v = dat.sizeBytes; + v = QVariant::fromValue(dat.sizeBytes); break; case ExplicitIndexCol: v = !dat.isSupportingIndex(); diff --git a/pglab/catalog/models/SequenceModel.cpp b/pglab/catalog/models/SequenceModel.cpp index 659348f..640b50c 100644 --- a/pglab/catalog/models/SequenceModel.cpp +++ b/pglab/catalog/models/SequenceModel.cpp @@ -102,12 +102,12 @@ QVariant SequenceModel::data(const QModelIndex &index, int role) const case NameCol: return seq.objectName(); case SchemaCol: return seq.nsName(); case OwnerCol: return seq.ownerName(); - case LastCol: return seq.last; - case StartCol: return seq.start; - case MinCol: return seq.min; - case MaxCol: return seq.max; - case IncrementCol: return seq.increment; - case CacheCol: return seq.cache; + case LastCol: return QVariant::fromValue(seq.last); + case StartCol: return QVariant::fromValue(seq.start); + case MinCol: return QVariant::fromValue(seq.min); + case MaxCol: return QVariant::fromValue(seq.max); + case IncrementCol: return QVariant::fromValue(seq.increment); + case CacheCol: return QVariant::fromValue(seq.cache); case CycledCol: return seq.cycled; case CalledCol: return seq.called; case AclCol: return seq.aclString(); diff --git a/pglab/catalog/tables/TablesTableModel.cpp b/pglab/catalog/tables/TablesTableModel.cpp index 0df8ff2..d6a4e8b 100644 --- a/pglab/catalog/tables/TablesTableModel.cpp +++ b/pglab/catalog/tables/TablesTableModel.cpp @@ -178,10 +178,10 @@ QVariant TablesTableModel::getData(const QModelIndex &index) const case OptionsCol: break; case AclCol: return t.aclString(); case CommentCol: return t.description; - case TotalSizeCol: return s.oid == 0 ? QVariant() : s.totalBytes; - case TableSizeCol: return s.oid == 0 ? QVariant() : s.totalBytes - s.indexBytes - s.toastBytes; - case IndexSizeCol: return s.oid == 0 ? QVariant() : s.indexBytes; - case ToastSizeCol: return s.oid == 0 ? QVariant() : s.toastBytes; + case TotalSizeCol: return s.oid == 0 ? QVariant() : QVariant::fromValue(s.totalBytes); + case TableSizeCol: return s.oid == 0 ? QVariant() : QVariant::fromValue(s.totalBytes - s.indexBytes - s.toastBytes); + case IndexSizeCol: return s.oid == 0 ? QVariant() : QVariant::fromValue(s.indexBytes); + case ToastSizeCol: return s.oid == 0 ? QVariant() : QVariant::fromValue(s.toastBytes); } return QVariant(); diff --git a/pglab/crud/CrudModel.cpp b/pglab/crud/CrudModel.cpp index d688bd6..8367f32 100644 --- a/pglab/crud/CrudModel.cpp +++ b/pglab/crud/CrudModel.cpp @@ -150,7 +150,7 @@ QVariant StringToVariant(const std::string &str, Oid oid) case Pgsql::oid_oid: case Pgsql::int8_oid: - return v.operator int64_t(); + return QVariant::fromValue(static_cast(v)); case Pgsql::bool_oid: return v.operator bool(); diff --git a/pglab/pglab.pro b/pglab/pglab.pro deleted file mode 100644 index 93a9186..0000000 --- a/pglab/pglab.pro +++ /dev/null @@ -1,229 +0,0 @@ -#------------------------------------------------- -# -# Project created by QtCreator 2016-11-11T09:17:13 -# -#------------------------------------------------- - -QT += core gui concurrent - -greaterThan(QT_MAJOR_VERSION, 4): QT += widgets sql - - -TARGET = pglab -TEMPLATE = app - -! include( ../common.pri ) { -error( "Couldn't find the common.pri file!" ) -} - -DEFINES += _WIN32_WINNT=0x0501 - -win32:RC_ICONS += pglab.ico - -SOURCES += main.cpp\ - About.cpp \ - catalog/delegates/IconColumnDelegate.cpp \ - catalog/models/BaseTableModel.cpp \ - catalog/models/ColumnTableModel.cpp \ - catalog/models/ConstraintModel.cpp \ - catalog/models/DatabasesTableModel.cpp \ - catalog/models/DependantsTableModel.cpp \ - catalog/models/IndexModel.cpp \ - catalog/models/ProcTableModel.cpp \ - catalog/models/RolesTableModel.cpp \ - catalog/models/SequenceModel.cpp \ - catalog/models/TriggerTableModel.cpp \ - catalog/tables/TablesTableModel.cpp \ - catalog/widgets/CatalogConstraintPage.cpp \ - catalog/widgets/CatalogFunctionsPage.cpp \ - catalog/widgets/CatalogIndexPage.cpp \ - catalog/widgets/CatalogInspector.cpp \ - catalog/widgets/CatalogNamespacePage.cpp \ - catalog/widgets/CatalogPageBase.cpp \ - catalog/widgets/CatalogSequencesPage.cpp \ - catalog/widgets/CatalogTablesPage.cpp \ - catalog/widgets/CatalogTypesPage.cpp \ - catalog/widgets/ColumnPage.cpp \ - catalog/widgets/DependantsPage.cpp \ - catalog/widgets/TriggerPage.cpp \ - codeeditor/CodeEditor.cpp \ - codeeditor/EditorGutter.cpp \ - codeeditor/GutterPainter.cpp \ - crud/CrudModel.cpp \ - crud/CrudTab.cpp \ - querytool/QueryExplainModel.cpp \ - querytool/QueryParamListController.cpp \ - querytool/QueryResultModel.cpp \ - querytool/QueryTool.cpp \ - serverinspector/DatabasesPage.cpp \ - serverinspector/RolesPage.cpp \ - serverinspector/ServerInspector.cpp \ - util/Colors.cpp \ - util/PgLabItemDelegate.cpp \ - util/PgLabTableView.cpp \ - util/SqlSyntaxHighlighter.cpp \ - ConnectionConfigurationWidget.cpp \ - ConnectionController.cpp \ - ManagedPage.cpp \ - PgDumpOutputHighlighter.cpp \ - CreateDatabaseDialog.cpp \ - ConnectionManagerWindow.cpp \ - ConnectionListModel.cpp \ - SslModeModel.cpp \ - stopwatch.cpp \ - TuplesResultWidget.cpp \ - BackupDialog.cpp \ - MasterController.cpp \ - ParamTypeDelegate.cpp \ - OpenDatabase.cpp \ - ProcessStdioWidget.cpp \ - ResultTableModelUtil.cpp \ - NamespaceItemModel.cpp \ - PropertyProxyModel.cpp \ - CodeGenerator.cpp \ - UserConfiguration.cpp \ - widgets/SqlCodePreview.cpp \ - CustomFilterSortModel.cpp \ - PropertiesPage.cpp \ - PasswordPromptDialog.cpp \ - EditTableWidget.cpp \ - EditColumnTableModel.cpp \ - DatabaseWindow.cpp \ - widgets/SingleRecordModel.cpp \ - widgets/SingleRecordWidget.cpp - -HEADERS += \ - About.h \ - Config.h \ - catalog/delegates/IconColumnDelegate.h \ - catalog/models/BaseTableModel.h \ - catalog/models/ColumnTableModel.h \ - catalog/models/ConstraintModel.h \ - catalog/models/DatabasesTableModel.h \ - catalog/models/DependantsTableModel.h \ - catalog/models/IndexModel.h \ - catalog/models/ProcTableModel.h \ - catalog/models/RolesTableModel.h \ - catalog/models/SequenceModel.h \ - catalog/models/TriggerTableModel.h \ - catalog/tables/TablesTableModel.h \ - catalog/widgets/CatalogConstraintPage.h \ - catalog/widgets/CatalogFunctionsPage.h \ - catalog/widgets/CatalogIndexPage.h \ - catalog/widgets/CatalogInspector.h \ - catalog/widgets/CatalogNamespacePage.h \ - catalog/widgets/CatalogPageBase.h \ - catalog/widgets/CatalogSequencesPage.h \ - catalog/widgets/CatalogTablesPage.h \ - catalog/widgets/CatalogTypesPage.h \ - catalog/widgets/ColumnPage.h \ - catalog/widgets/DependantsPage.h \ - catalog/widgets/TriggerPage.h \ - codeeditor/CodeEditor.h \ - codeeditor/EditorGutter.h \ - codeeditor/GutterPainter.h \ - crud/CrudModel.h \ - crud/CrudTab.h \ - querytool/QueryExplainModel.h \ - querytool/QueryParamListController.h \ - querytool/QueryResultModel.h \ - querytool/QueryTool.h \ - serverinspector/DatabasesPage.h \ - serverinspector/RolesPage.h \ - serverinspector/ServerInspector.h \ - util/Colors.h \ - util/PgLabItemDelegate.h \ - util/PgLabTableView.h \ - util/PgLabTableViewHelper.h \ - util/SqlSyntaxHighlighter.h \ - ConnectionConfigurationWidget.h \ - ConnectionController.h \ - IDatabaseWindow.h \ - ManagedPage.h \ - PgDumpOutputHighlighter.h \ - CreateDatabaseDialog.h \ - ConnectionManagerWindow.h \ - ConnectionListModel.h \ - SslModeModel.h \ - stopwatch.h \ - TuplesResultWidget.h \ - BackupDialog.h \ - MasterController.h \ - ParamTypeDelegate.h \ - OpenDatabase.h \ - ProcessStdioWidget.h \ - ResultTableModelUtil.h \ - NamespaceItemModel.h \ - AbstractCommand.h \ - PropertyProxyModel.h \ - CustomDataRole.h \ - CodeGenerator.h \ - UserConfiguration.h \ - widgets/SqlCodePreview.h \ - CustomFilterSortModel.h \ - PropertiesPage.h \ - PasswordPromptDialog.h \ - EditTableWidget.h \ - EditColumnTableModel.h \ - DatabaseWindow.h \ - NamespaceFilter.h \ - widgets/SingleRecordModel.h \ - widgets/SingleRecordWidget.h - -FORMS += \ - ConnectionManagerWindow.ui \ - CreateDatabaseDialog.ui \ - DatabaseWindow.ui \ - TuplesResultWidget.ui \ - querytool/QueryTab.ui \ - ProcessStdioWidget.ui \ - crud/CrudTab.ui \ - CodeGenerator.ui \ - widgets/SingleRecordWidget.ui - -RESOURCES += \ - resources.qrc - -#QMAKE_LFLAGS_WINDOWS = /SUBSYSTEM:WINDOWS,5.01 - -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 += $$PWD/../core -DEPENDPATH += $$PWD/../core - -win32:CONFIG(debug, debug|release): LIBS += -lbotand -else:win32:CONFIG(release, debug|release): LIBS += -lbotan - -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 - - -win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../pgsql/release/ -lpgsql -else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../pgsql/debug/ -lpgsql -else:unix:!macx: LIBS += -L$$OUT_PWD/../pgsql/ -lpgsql - -INCLUDEPATH += $$PWD/../pgsql -DEPENDPATH += $$PWD/../pgsql - -win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../pgsql/release/libpgsql.a -else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../pgsql/debug/libpgsql.a -else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../pgsql/release/pgsql.lib -else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../pgsql/debug/pgsql.lib -else:unix:!macx: PRE_TARGETDEPS += $$OUT_PWD/../pgsql/libpgsql.a - - -win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../pglablib/release/ -lpglablib -else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../pglablib/debug/ -lpglablib -else:unix:!macx: LIBS += -L$$OUT_PWD/../pglablib/ -lpglablib - -INCLUDEPATH += $$PWD/../pglablib -DEPENDPATH += $$PWD/../pglablib - -win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../pglablib/release/libpglablib.a -else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../pglablib/debug/libpglablib.a -else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../pglablib/release/pglablib.lib -else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../pglablib/debug/pglablib.lib -else:unix:!macx: PRE_TARGETDEPS += $$OUT_PWD/../pglablib/libpglablib.a diff --git a/pglab/querytool/QueryExplainModel.cpp b/pglab/querytool/QueryExplainModel.cpp index 51381ec..bcce73b 100644 --- a/pglab/querytool/QueryExplainModel.cpp +++ b/pglab/querytool/QueryExplainModel.cpp @@ -40,7 +40,7 @@ if (role == Qt::DisplayRole) { result = item->estimateError(); break; case c_ColumnRowCount: - result = item->actualRows; + result = QVariant::fromValue(item->actualRows); break; case c_ColumnLoops: result = item->actualLoops; diff --git a/pglabAll.pro b/pglabAll.pro deleted file mode 100644 index 8631a5e..0000000 --- a/pglabAll.pro +++ /dev/null @@ -1,18 +0,0 @@ -TEMPLATE = subdirs - -DEFINES += BOOST_ENABLE_ASSERT_HANDLER - -SUBDIRS += core \ - pgsql \ - pglablib \ - pglab - -pglab.depends = core pgsql pglablib -pgsql.depends = core -pglablib.depends = core pgsql -tests.depends = core pgsql pglablib - - -CONFIG(debug, debug|release) { -SUBDIRS += tests -} diff --git a/pglablib/ASyncDBConnection.cpp b/pglablib/ASyncDBConnection.cpp index 1c27fb9..2b5c2fb 100644 --- a/pglablib/ASyncDBConnection.cpp +++ b/pglablib/ASyncDBConnection.cpp @@ -1,13 +1,14 @@ -#include "ASyncDBConnection.h" +#include "ASyncDBConnection.h" #include "ScopeGuard.h" #include "util.h" #include "Pgsql_PgException.h" -#include "Win32Event.h" -#include "WaitHandleList.h" +#include #include #include -#include #include +#include +#include +#include namespace { @@ -45,10 +46,6 @@ public: 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; ConnectionConfig m_config; @@ -64,18 +61,29 @@ public: void stop(); + /// Wakes the worker thread when it is waiting in its event loop + void wake(); + private: + enum class WaitResult { + Socket, ///< the socket became ready + Wakeup, ///< woken up by stop() or by a new command + Timeout ///< the timeout expired + }; + ASyncDBConnection *asyncConnObject = nullptr; - /// \todo Implement new method to stop the thread - Win32Event m_stopEvent; + std::atomic terminateRequested{false}; ///< is set when the thread should stop + std::mutex m_wakeMutex; + QEventLoop *m_loop = nullptr; ///< loop the worker blocks in, guarded by m_wakeMutex 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 hasQueuedCommand(); + WaitResult waitForSocket(QSocketNotifier::Type type, int timeout_ms, bool wakeOnNewCommand); bool makeConnection(); void communicate(); @@ -97,7 +105,6 @@ private: ASyncDBConnectionThread::ASyncDBConnectionThread(ASyncDBConnection *asco) : asyncConnObject(asco) - , m_stopEvent(Win32Event::Reset::Manual, Win32Event::Initial::Clear) {} void ASyncDBConnectionThread::run() @@ -154,6 +161,59 @@ bool ASyncDBConnectionThread::cancel() return m_canceller.cancel(nullptr); } +bool ASyncDBConnectionThread::hasQueuedCommand() +{ + std::lock_guard lg(m_commandQueue.m_mutex); + return !m_commandQueue.m_queue.empty(); +} + +ASyncDBConnectionThread::WaitResult ASyncDBConnectionThread::waitForSocket(QSocketNotifier::Type type, int timeout_ms, bool wakeOnNewCommand) +{ + QEventLoop loop; + WaitResult result = WaitResult::Wakeup; + + QSocketNotifier notifier(m_connection.socket(), type); + QObject::connect(¬ifier, &QSocketNotifier::activated, &loop, [&result, &loop] { + result = WaitResult::Socket; + loop.quit(); + }); + + QTimer timer; + timer.setSingleShot(true); + if (timeout_ms >= 0) { + QObject::connect(&timer, &QTimer::timeout, &loop, [&result, &loop] { + result = WaitResult::Timeout; + loop.quit(); + }); + timer.start(timeout_ms); + } + + { + std::lock_guard lg(m_wakeMutex); + m_loop = &loop; + } + + // Checked after publishing the loop, so a wake-up that happened before is not lost + bool pending = terminateRequested || (wakeOnNewCommand && hasQueuedCommand()); + if (!pending) { + loop.exec(); + } + + { + std::lock_guard lg(m_wakeMutex); + m_loop = nullptr; + } + return result; +} + +void ASyncDBConnectionThread::wake() +{ + std::lock_guard lg(m_wakeMutex); + if (m_loop) { + QMetaObject::invokeMethod(m_loop, [loop = m_loop] { loop->quit(); }, Qt::QueuedConnection); + } +} + bool ASyncDBConnectionThread::makeConnection() { using namespace std::literals::chrono_literals; @@ -165,30 +225,14 @@ bool ASyncDBConnectionThread::makeConnection() bool ok = m_connection.connectStart(conn_string); //keywords, values); auto start = std::chrono::steady_clock::now(); if (ok && m_connection.status() != CONNECTION_BAD) { - Win32Event socket_event(Win32Event::Reset::Auto, Win32Event::Initial::Clear); - - long fd = FD_WRITE; + QSocketNotifier::Type type = QSocketNotifier::Write; while (true) { // poll till complete or failed (we can get an abort command) - int sock = m_connection.socket(); - 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 elapsed = std::chrono::steady_clock::now() - start; + auto remaining = std::chrono::duration_cast(30s - elapsed).count(); + WaitResult res = waitForSocket(type, remaining > 0 ? static_cast(remaining) : 0, false); - 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) { + if (res == WaitResult::Socket) { auto poll_state = m_connection.connectPoll(); if (poll_state == PGRES_POLLING_OK) { qDebug() << "ASyncDBConnection Connected"; @@ -202,17 +246,21 @@ bool ASyncDBConnectionThread::makeConnection() } else if (poll_state == PGRES_POLLING_READING) { doStateCallback({ ASyncDBConnection::State::Connecting, "Negotiating" }); - fd = FD_READ; + type = QSocketNotifier::Read; } else if (poll_state == PGRES_POLLING_WRITING) { doStateCallback({ ASyncDBConnection::State::Connecting, "Negotiating" }); - fd = FD_WRITE; + type = QSocketNotifier::Write; } } - else if (res == wait_result_stop) { + else if (terminateRequested) { + m_connection.close(); + return false; + } + else if (res == WaitResult::Timeout) { + doStateCallback({ ASyncDBConnection::State::NotConnected, "Connection timed out" }); m_connection.close(); return false; - } } // end while (true) } @@ -252,7 +300,7 @@ void ASyncDBConnectionThread::communicate() void ASyncDBConnectionThread::stop() { terminateRequested = true; - m_stopEvent.set(); + wake(); } void ASyncDBConnectionThread::doStateCallback(ASyncDBConnection::StateData state) @@ -264,34 +312,18 @@ void ASyncDBConnectionThread::doStateCallback(ASyncDBConnection::StateData state bool ASyncDBConnectionThread::waitForAndSendCommand() { - SOCKET sock = static_cast(m_connection.socket()); - Win32Event socket_event(Win32Event::Reset::Manual, Win32Event::Initial::Clear); - long fd = FD_READ | FD_CLOSE; - WSAEventSelect(sock, socket_event.handle(), fd); - - WaitHandleList whl; - auto wait_result_new_command = whl.add(m_commandQueue.m_newEvent); - auto wait_result_socket = whl.add(socket_event); - 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) { + if (hasQueuedCommand()) { doNewCommand(); + return true; + } + + // Idle connection: a readable socket carries notifies or notices, or signals a lost connection + if (waitForSocket(QSocketNotifier::Read, -1, true) == WaitResult::Socket) { + if (!m_connection.consumeInput()) { + doStateCallback({ ASyncDBConnection::State::NotConnected, "Connection lost" }); + return false; + } } - else if (res == wait_result_socket) { - WSANETWORKEVENTS net_events; - WSAEnumNetworkEvents(sock, socket_event.handle(), &net_events); - if (net_events.lNetworkEvents & FD_CLOSE) { - doStateCallback({ ASyncDBConnection::State::NotConnected, "Connection lost" }); - return false; - } - } // Note if it was stop we can just return and function // above will stop looping because terminateRequested has been set too by stop return true; @@ -347,42 +379,16 @@ bool ASyncDBConnectionThread::consumeResultInput() void ASyncDBConnectionThread::waitForResult() { - SOCKET sock = static_cast(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); + WaitResult res = waitForSocket(QSocketNotifier::Read, -1, false); - 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 (consumeResultInput()) { - finished = true; - } + if (res == WaitResult::Socket) { + if (consumeResultInput()) { + finished = true; } - else if (net_events.lNetworkEvents & FD_CLOSE) { - doStateCallback({ ASyncDBConnection::State::NotConnected, "Close while waiting for result" }); - finished = true; - stop(); - } } - if (res == wait_result_stop) { + else if (terminateRequested) { // Send cancel, close connection and terminate thread cancel(); doStateCallback(ASyncDBConnection::State::Terminating); @@ -455,8 +461,8 @@ bool ASyncDBConnection::send(const std::string &command, on_result_callback on_r { 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(); } + m_threadData->wake(); return true; } @@ -468,8 +474,8 @@ bool ASyncDBConnection::send(const std::string &command, Pgsql::Params params, o { 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(); } + m_threadData->wake(); return true; } diff --git a/pglablib/ASyncDBConnection.h b/pglablib/ASyncDBConnection.h index 02f5310..0479f5f 100644 --- a/pglablib/ASyncDBConnection.h +++ b/pglablib/ASyncDBConnection.h @@ -11,6 +11,7 @@ #include #include #include +#include class ASyncDBConnectionThread; /** \brief Class that handles asynchronous execution of queries. @@ -33,7 +34,7 @@ public: class StateData { public: - State State; + enum State State; QString Message; StateData(enum State state, QString message = QString()) diff --git a/pglablib/CMakeLists.txt b/pglablib/CMakeLists.txt new file mode 100644 index 0000000..a3c759d --- /dev/null +++ b/pglablib/CMakeLists.txt @@ -0,0 +1,187 @@ +add_library(pglablib STATIC + Pglablib.cpp + ASyncDBConnection.cpp + ConnectionConfig.cpp + TestConnection.cpp + catalog/PgType.cpp + catalog/PgTypeContainer.cpp + catalog/PgNamespace.cpp + catalog/PgClass.cpp + catalog/PgDatabase.cpp + catalog/PgDatabaseContainer.cpp + catalog/PgAuthId.cpp + catalog/PgAuthIdContainer.cpp + catalog/PgClassContainer.cpp + catalog/PgDatabaseCatalog.cpp + catalog/PgNamespaceContainer.cpp + catalog/PgAttribute.cpp + catalog/PgContainer.cpp + catalog/PgAttributeContainer.cpp + catalog/PgIndex.cpp + catalog/PgIndexContainer.cpp + catalog/PgConstraint.cpp + catalog/PgConstraintContainer.cpp + ParamListJson.cpp + ParamListModel.cpp + sqlite/SQLiteConnection.cpp + sqlite/sqlite3.c + ui/catalog/tables/TableNode.cpp + ui/catalog/tables/TableSize.cpp + ui/catalog/tables/TableTreeBuilder.cpp + util.cpp + SqlFormattingUtils.cpp + catalog/PgKeywordList.cpp + QueryGenerator.cpp + catalog/PgObject.cpp + catalog/PgTablespace.cpp + catalog/PgTablespaceContainer.cpp + codebuilder/LanguageConfig.cpp + codebuilder/CodeBuilder.cpp + codebuilder/NameManglingRules.cpp + codebuilder/DefaultConfigs.cpp + codebuilder/TypeMappings.cpp + codebuilder/IndentationConfig.cpp + codebuilder/StructureTemplate.cpp + FormatToStream.cpp + codebuilder/StringLiteralRules.cpp + codebuilder/StringEscapeRule.cpp + catalog/PgTrigger.cpp + catalog/PgTriggerContainer.cpp + catalog/PgProc.cpp + catalog/PgProcContainer.cpp + catalog/PgDatabaseObject.cpp + catalog/PgServerObject.cpp + catalog/PgNamespaceObject.cpp + catalog/PgCollation.cpp + catalog/PgCollationContainer.cpp + catalog/PgInherits.cpp + catalog/PgInheritsContainer.cpp + SelectionEditorFactory.cpp + catalog/PgAm.cpp + model/TypeModelFactory.cpp + model/TypeSelectionItemModel.cpp + catalog/PgAmContainer.cpp + model/CollationModel.cpp + model/CollationModelFactory.cpp + catalog/PgLanguageContainer.cpp + catalog/PgLanguage.cpp + catalog/PgAcl.cpp + catalog/PgSequence.cpp + catalog/PgSequenceContainer.cpp + utils/HumanReadableBytes.cpp + utils/KeyStrengthener.cpp + utils/PasswordManager.cpp + utils/PostgresqlUrlParser.cpp + Pglablib.h + ASyncDBConnection.h + ConnectionConfig.h + TestConnection.h + catalog/PgType.h + catalog/PgTypeContainer.h + catalog/PgNamespace.h + catalog/PgClass.h + catalog/PgDatabase.h + catalog/PgDatabaseContainer.h + catalog/PgContainer.h + catalog/PgAuthId.h + catalog/PgAuthIdContainer.h + catalog/PgClassContainer.h + catalog/PgDatabaseCatalog.h + catalog/PgNamespaceContainer.h + catalog/PgAttribute.h + catalog/PgAttributeContainer.h + catalog/PgIndex.h + catalog/PgIndexContainer.h + catalog/PgConstraint.h + catalog/PgConstraintContainer.h + ParamListJson.h + ParamListModel.h + sqlite/SQLiteConnection.h + sqlite/sqlite3.h + sqlite/sqlite3ext.h + ui/catalog/tables/TableNode.h + ui/catalog/tables/TableSize.h + ui/catalog/tables/TableTreeBuilder.h + util.h + SqlFormattingUtils.h + catalog/PgCatalogTypes.h + catalog/PgKeywordList.h + QueryGenerator.h + catalog/PgObject.h + catalog/PgTablespace.h + catalog/PgTablespaceContainer.h + codebuilder/LanguageConfig.h + codebuilder/CodeBuilder.h + codebuilder/NameManglingRules.h + codebuilder/DefaultConfigs.h + codebuilder/TypeMappings.h + codebuilder/IndentationConfig.h + codebuilder/StructureTemplate.h + FormatToStream.h + codebuilder/ResultLoopTemplate.h + codebuilder/StringEscapeRule.h + codebuilder/StringLiteralRules.h + catalog/PgTrigger.h + catalog/PgTriggerContainer.h + catalog/PgProc.h + catalog/PgProcContainer.h + catalog/PgDatabaseObject.h + catalog/PgServerObject.h + catalog/PgNamespaceObject.h + catalog/PgCollation.h + catalog/PgCollationContainer.h + AbstractModelFactory.h + AbstractEditorFactory.h + catalog/PgInherits.h + catalog/PgInheritsContainer.h + SelectionEditorFactory.h + model/TypeSelectionItemModel.h + model/TypeModelFactory.h + catalog/PgAm.h + catalog/PgAmContainer.h + model/CollationModel.h + model/CollationModelFactory.h + catalog/PgLanguageContainer.h + catalog/PgLanguage.h + catalog/PgAcl.h + catalog/PgSequence.h + catalog/PgSequenceContainer.h + utils/HumanReadableBytes.h + utils/KeyStrengthener.h + utils/PasswordManager.h + utils/PostgresqlUrlParser.h + ) + +find_package(Boost REQUIRED COMPONENTS container timer chrono assert) + +find_path(BOTAN_INCLUDE_DIR botan/hash.h REQUIRED) +find_library(BOTAN_LIBRARY NAMES botan-3 botan REQUIRED) +if(NOT TARGET Botan::Botan) + add_library(Botan::Botan STATIC IMPORTED) + set_target_properties(Botan::Botan PROPERTIES + IMPORTED_LOCATION "${BOTAN_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${BOTAN_INCLUDE_DIR}" + ) +endif() + +target_link_libraries(pglablib PUBLIC + core + pgsql + Boost::container + Boost::timer + Boost::chrono + Boost::assert + Botan::Botan + Qt6::Core + Qt6::Widgets + ) + +target_include_directories(pglablib PUBLIC + $ + ) + +set_target_properties(pglablib PROPERTIES + CXX_STANDARD 20 + CXX_STANDARD_REQUIRED ON + POSITION_INDEPENDENT_CODE ON + ) diff --git a/pglablib/SqlFormattingUtils.cpp b/pglablib/SqlFormattingUtils.cpp index a75620e..ff7f1d3 100644 --- a/pglablib/SqlFormattingUtils.cpp +++ b/pglablib/SqlFormattingUtils.cpp @@ -200,7 +200,7 @@ QString quoteIdent(QString ident) { assert(ident.length() > 0); - static const wchar_t dquote = L'"'; + static const QChar dquote = u'"'; if (identNeedsQuotes(ident)) { QString out; diff --git a/pglablib/WaitHandleList.cpp b/pglablib/WaitHandleList.cpp deleted file mode 100644 index d219610..0000000 --- a/pglablib/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/pglablib/WaitHandleList.h b/pglablib/WaitHandleList.h deleted file mode 100644 index 376e817..0000000 --- a/pglablib/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/pglablib/Win32Event.h b/pglablib/Win32Event.h deleted file mode 100644 index 684d13f..0000000 --- a/pglablib/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/pglablib/catalog/PgLanguage.cpp b/pglablib/catalog/PgLanguage.cpp index cd9dd4f..c224d23 100644 --- a/pglablib/catalog/PgLanguage.cpp +++ b/pglablib/catalog/PgLanguage.cpp @@ -1,13 +1,15 @@ #include "PgLanguage.h" +#include + QString PgLanguage::createSql() const { - throw std::exception("PgLanguage::createSql() not implemented"); + throw std::logic_error("PgLanguage::createSql() not implemented"); } QString PgLanguage::dropSql() const { - throw std::exception("PgLanguage::dropSql() not implemented"); + throw std::logic_error("PgLanguage::dropSql() not implemented"); } QString PgLanguage::typeName() const diff --git a/pglablib/catalog/PgProc.cpp b/pglablib/catalog/PgProc.cpp index 83fe734..02cf6d0 100644 --- a/pglablib/catalog/PgProc.cpp +++ b/pglablib/catalog/PgProc.cpp @@ -48,15 +48,15 @@ namespace { for(; index < len; index++) { QChar ch = str[index]; - if (!double_quote && ch == L'\'') + if (!double_quote && ch == u'\'') single_quote = !single_quote; - else if (!single_quote && ch == L'"') + else if (!single_quote && ch == u'"') double_quote = !double_quote; - else if (!double_quote && !single_quote && ch == L'(') + else if (!double_quote && !single_quote && ch == u'(') brackets++; - else if (!double_quote && !single_quote && ch == L')') + else if (!double_quote && !single_quote && ch == u')') brackets--; - else if (!double_quote && !single_quote && brackets == 0 && ch == L',') { + else if (!double_quote && !single_quote && brackets == 0 && ch == u',') { if (index != start_array) res.push_back(str.mid(start_array, index - 1).trimmed()); else diff --git a/pglablib/catalog/PgServerObject.cpp b/pglablib/catalog/PgServerObject.cpp index f85bd1f..1108917 100644 --- a/pglablib/catalog/PgServerObject.cpp +++ b/pglablib/catalog/PgServerObject.cpp @@ -38,7 +38,7 @@ QString PgServerObject::alterOwnerSql(const QString& ident) const } -void PgServerObject::setAcls(boost::optional acls) +void PgServerObject::setAcls(std::optional acls) { m_acls = std::move(acls); } diff --git a/pglablib/catalog/PgServerObject.h b/pglablib/catalog/PgServerObject.h index 5c08fd3..b1520a1 100644 --- a/pglablib/catalog/PgServerObject.h +++ b/pglablib/catalog/PgServerObject.h @@ -4,7 +4,7 @@ #include #include "PgObject.h" #include "PgAcl.h" -#include +#include class PgAuthId; @@ -26,7 +26,7 @@ public: * @brief setAcls * @param acls Important: pass empty optional when acl IS NULL, pass empty list for empty array */ - void setAcls(boost::optional acls); + void setAcls(std::optional acls); QString aclString() const; /** * @brief grantSql @@ -53,7 +53,7 @@ protected: private: Oid m_ownerOid = InvalidOid; const PgAuthId * m_owner = nullptr; - boost::optional m_acls; + std::optional m_acls; }; #endif // PGSERVEROBJECT_H diff --git a/pglablib/codebuilder/StringEscapeRule.h b/pglablib/codebuilder/StringEscapeRule.h index a8c9822..fb01dd8 100644 --- a/pglablib/codebuilder/StringEscapeRule.h +++ b/pglablib/codebuilder/StringEscapeRule.h @@ -2,7 +2,6 @@ #define STRINGESCAPERULE_H #include -#include enum class ConvertToNumericEscape { Utf8, ///< Generates upto four escapes for 4 utf8 chars diff --git a/pglablib/pglablib.pro b/pglablib/pglablib.pro deleted file mode 100644 index c41f973..0000000 --- a/pglablib/pglablib.pro +++ /dev/null @@ -1,222 +0,0 @@ -#------------------------------------------------- -# -# Project created by QtCreator 2017-12-13T17:36:43 -# -#------------------------------------------------- - -QT += widgets core - -TARGET = pglablib -TEMPLATE = lib -CONFIG += staticlib - -! include( ../common.pri ) { -error( "Couldn't find the common.pri file!" ) -} - -# 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 += \ - Pglablib.cpp \ - ASyncDBConnection.cpp \ - ConnectionConfig.cpp \ - TestConnection.cpp \ - WaitHandleList.cpp \ - catalog/PgType.cpp \ - catalog/PgTypeContainer.cpp \ - catalog/PgNamespace.cpp \ - catalog/PgClass.cpp \ - catalog/PgDatabase.cpp \ - catalog/PgDatabaseContainer.cpp \ - catalog/PgAuthId.cpp \ - catalog/PgAuthIdContainer.cpp \ - catalog/PgClassContainer.cpp \ - catalog/PgDatabaseCatalog.cpp \ - catalog/PgNamespaceContainer.cpp \ - catalog/PgAttribute.cpp \ - catalog/PgContainer.cpp \ - catalog/PgAttributeContainer.cpp \ - catalog/PgIndex.cpp \ - catalog/PgIndexContainer.cpp \ - catalog/PgConstraint.cpp \ - catalog/PgConstraintContainer.cpp \ - ParamListJson.cpp \ - ParamListModel.cpp \ - sqlite/SQLiteConnection.cpp \ - sqlite/sqlite3.c \ - ui/catalog/tables/TableNode.cpp \ - ui/catalog/tables/TableSize.cpp \ - ui/catalog/tables/TableTreeBuilder.cpp \ - util.cpp \ - SqlFormattingUtils.cpp \ - catalog/PgKeywordList.cpp \ - QueryGenerator.cpp \ - catalog/PgObject.cpp \ - catalog/PgTablespace.cpp \ - catalog/PgTablespaceContainer.cpp \ - codebuilder/LanguageConfig.cpp \ - codebuilder/CodeBuilder.cpp \ - codebuilder/NameManglingRules.cpp \ - codebuilder/DefaultConfigs.cpp \ - codebuilder/TypeMappings.cpp \ - codebuilder/IndentationConfig.cpp \ - codebuilder/StructureTemplate.cpp \ - FormatToStream.cpp \ - codebuilder/StringLiteralRules.cpp \ - codebuilder/StringEscapeRule.cpp \ - catalog/PgTrigger.cpp \ - catalog/PgTriggerContainer.cpp \ - catalog/PgProc.cpp \ - catalog/PgProcContainer.cpp \ - catalog/PgDatabaseObject.cpp \ - catalog/PgServerObject.cpp \ - catalog/PgNamespaceObject.cpp \ - catalog/PgCollation.cpp \ - catalog/PgCollationContainer.cpp \ - catalog/PgInherits.cpp \ - catalog/PgInheritsContainer.cpp \ - SelectionEditorFactory.cpp \ - catalog/PgAm.cpp \ - model/TypeModelFactory.cpp \ - model/TypeSelectionItemModel.cpp \ - catalog/PgAmContainer.cpp \ - model/CollationModel.cpp \ - model/CollationModelFactory.cpp \ - catalog/PgLanguageContainer.cpp \ - catalog/PgLanguage.cpp \ - catalog/PgAcl.cpp \ - catalog/PgSequence.cpp \ - catalog/PgSequenceContainer.cpp \ - utils/HumanReadableBytes.cpp \ - utils/KeyStrengthener.cpp \ - utils/PasswordManager.cpp \ - utils/PostgresqlUrlParser.cpp - -HEADERS += \ - Pglablib.h \ - ASyncDBConnection.h \ - ConnectionConfig.h \ - TestConnection.h \ - WaitHandleList.h \ - Win32Event.h \ - catalog/PgType.h \ - catalog/PgTypeContainer.h \ - catalog/PgNamespace.h \ - catalog/PgClass.h \ - catalog/PgDatabase.h \ - catalog/PgDatabaseContainer.h \ - catalog/PgContainer.h \ - catalog/PgAuthId.h \ - catalog/PgAuthIdContainer.h \ - catalog/PgClassContainer.h \ - catalog/PgDatabaseCatalog.h \ - catalog/PgNamespaceContainer.h \ - catalog/PgAttribute.h \ - catalog/PgAttributeContainer.h \ - catalog/PgIndex.h \ - catalog/PgIndexContainer.h \ - catalog/PgConstraint.h \ - catalog/PgConstraintContainer.h \ - ParamListJson.h \ - ParamListModel.h \ - sqlite/SQLiteConnection.h \ - sqlite/sqlite3.h \ - sqlite/sqlite3ext.h \ - ui/catalog/tables/TableNode.h \ - ui/catalog/tables/TableSize.h \ - ui/catalog/tables/TableTreeBuilder.h \ - util.h \ - SqlFormattingUtils.h \ - catalog/PgCatalogTypes.h \ - catalog/PgKeywordList.h \ - QueryGenerator.h \ - catalog/PgObject.h \ - catalog/PgTablespace.h \ - catalog/PgTablespaceContainer.h \ - codebuilder/LanguageConfig.h \ - codebuilder/CodeBuilder.h \ - codebuilder/NameManglingRules.h \ - codebuilder/DefaultConfigs.h \ - codebuilder/TypeMappings.h \ - codebuilder/IndentationConfig.h \ - codebuilder/StructureTemplate.h \ - FormatToStream.h \ - codebuilder/ResultLoopTemplate.h \ - codebuilder/StringEscapeRule.h \ - codebuilder/StringLiteralRules.h \ - catalog/PgTrigger.h \ - catalog/PgTriggerContainer.h \ - catalog/PgProc.h \ - catalog/PgProcContainer.h \ - catalog/PgDatabaseObject.h \ - catalog/PgServerObject.h \ - catalog/PgNamespaceObject.h \ - catalog/PgCollation.h \ - catalog/PgCollationContainer.h \ - AbstractModelFactory.h \ - AbstractEditorFactory.h \ - catalog/PgInherits.h \ - catalog/PgInheritsContainer.h \ - SelectionEditorFactory.h \ - model/TypeSelectionItemModel.h \ - model/TypeModelFactory.h \ - catalog/PgAm.h \ - catalog/PgAmContainer.h \ - model/CollationModel.h \ - model/CollationModelFactory.h \ - catalog/PgLanguageContainer.h \ - catalog/PgLanguage.h \ - catalog/PgAcl.h \ - catalog/PgSequence.h \ - catalog/PgSequenceContainer.h \ - utils/HumanReadableBytes.h \ - utils/KeyStrengthener.h \ - utils/PasswordManager.h \ - utils/PostgresqlUrlParser.h - -unix { - target.path = /usr/lib - INSTALLS += target -} - -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 -else:unix:!macx: LIBS += -L$$OUT_PWD/../core/ -lcore - -INCLUDEPATH += $$PWD/../core -DEPENDPATH += $$PWD/../core - -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 -else:unix:!macx: PRE_TARGETDEPS += $$OUT_PWD/../core/libcore.a - -win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../pgsql/release/ -lpgsql -else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../pgsql/debug/ -lpgsql -else:unix:!macx: LIBS += -L$$OUT_PWD/../pgsql/ -lpgsql - -INCLUDEPATH += $$PWD/../pgsql -DEPENDPATH += $$PWD/../pgsql - -win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../pgsql/release/libpgsql.a -else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../pgsql/debug/libpgsql.a -else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../pgsql/release/pgsql.lib -else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../pgsql/debug/pgsql.lib -else:unix:!macx: PRE_TARGETDEPS += $$OUT_PWD/../pgsql/libpgsql.a - -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 -else:unix: LIBS += -L$$OUT_PWD/../core/ -lcore - -INCLUDEPATH += $$PWD/../core -DEPENDPATH += $$PWD/../core - -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 -else:unix: PRE_TARGETDEPS += $$OUT_PWD/../core/libcore.a diff --git a/pglablib/utils/HumanReadableBytes.h b/pglablib/utils/HumanReadableBytes.h index b76de05..b17ec0f 100644 --- a/pglablib/utils/HumanReadableBytes.h +++ b/pglablib/utils/HumanReadableBytes.h @@ -1,5 +1,6 @@ #pragma once +#include #include std::string HumanReadableBytes(uint64_t bytes); diff --git a/pglablib/utils/PasswordManager.cpp b/pglablib/utils/PasswordManager.cpp index b0a71de..dfa0476 100644 --- a/pglablib/utils/PasswordManager.cpp +++ b/pglablib/utils/PasswordManager.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include using namespace Botan; @@ -33,7 +33,7 @@ public: * distinct key which is derived by hashing the wrapped key name with HMAC. */ const std::vector wrapped_name = - nist_key_wrap_padded(cast_char_ptr_to_uint8(name.data()), + nist_key_wrap_padded(reinterpret_cast(name.data()), name.size(), *m_cipher); @@ -47,7 +47,7 @@ public: secure_vector get(const std::string& name, const std::string_view &wrapped_key) const { const std::vector wrapped_name = - nist_key_wrap_padded(cast_char_ptr_to_uint8(name.data()), + nist_key_wrap_padded(reinterpret_cast(name.data()), name.size(), *m_cipher); diff --git a/pglablib/utils/PasswordManager.h b/pglablib/utils/PasswordManager.h index 4bba574..8fb99d1 100644 --- a/pglablib/utils/PasswordManager.h +++ b/pglablib/utils/PasswordManager.h @@ -19,7 +19,11 @@ namespace Botan { class PasswordManagerException: public std::exception { public: - using std::exception::exception; //(char const* const _Message); + PasswordManagerException() = default; + explicit PasswordManagerException(const char *message) : m_message(message) {} + const char *what() const noexcept override { return m_message.c_str(); } +private: + std::string m_message; }; class PasswordManagerLockedException: public PasswordManagerException { diff --git a/pgsql/ArrayParser.cpp b/pgsql/ArrayParser.cpp index 1f29a61..cdb5999 100644 --- a/pgsql/ArrayParser.cpp +++ b/pgsql/ArrayParser.cpp @@ -1,4 +1,5 @@ #include "ArrayParser.h" +#include #include using namespace Pgsql; diff --git a/pgsql/CMakeLists.txt b/pgsql/CMakeLists.txt new file mode 100644 index 0000000..f6b0f39 --- /dev/null +++ b/pgsql/CMakeLists.txt @@ -0,0 +1,48 @@ +find_package(PostgreSQL REQUIRED) + +add_library(pgsql STATIC + Pgsql_Connection.cpp + Pgsql_Params.cpp + Pgsql_PgException.cpp + Pgsql_Result.cpp + Pgsql_Row.cpp + Pgsql_Value.cpp + ArrayParser.cpp + Pgsql_oids.cpp + Pgsql_Transaction.cpp + Pgsql_ErrorDetails.cpp + Pgsql_Canceller.cpp + Pgsql_Connection.h + Pgsql_IResult.h + Pgsql_Params.h + Pgsql_PgException.h + Pgsql_Result.h + Pgsql_ResultConstIterator.h + Pgsql_Row.h + Pgsql_Value.h + Pgsql_declare.h + Pgsql_Col.h + ArrayParser.h + Pgsql_oids.h + SqlGenerator.h + Pgsql_Transaction.h + Pgsql_ErrorDetails.h + Pgsql_Canceller.h + ) + +target_link_libraries(pgsql PUBLIC + core + PostgreSQL::PostgreSQL + Qt6::Core + Qt6::Widgets + ) + +target_include_directories(pgsql PUBLIC + $ + ) + +set_target_properties(pgsql PROPERTIES + CXX_STANDARD 20 + CXX_STANDARD_REQUIRED ON + POSITION_INDEPENDENT_CODE ON + ) diff --git a/pgsql/pgsql.pro b/pgsql/pgsql.pro deleted file mode 100644 index 02c21a5..0000000 --- a/pgsql/pgsql.pro +++ /dev/null @@ -1,60 +0,0 @@ -#------------------------------------------------- -# -# Project created by QtCreator 2016-11-11T09:17:13 -# -#------------------------------------------------- - -CONFIG += staticlib -QT += core - -greaterThan(QT_MAJOR_VERSION, 4): QT += widgets - -TARGET = pgsql -TEMPLATE = lib - -! include( ../common.pri ) { -error( "Couldn't find the common.pri file!" ) -} - -LIBS += -lws2_32 -llibpq - -SOURCES += Pgsql_Connection.cpp \ - Pgsql_Params.cpp \ - Pgsql_PgException.cpp \ - Pgsql_Result.cpp \ - Pgsql_Row.cpp \ - Pgsql_Value.cpp \ - ArrayParser.cpp \ - Pgsql_oids.cpp \ - Pgsql_Transaction.cpp \ - Pgsql_ErrorDetails.cpp \ - Pgsql_Canceller.cpp - -HEADERS += Pgsql_Connection.h \ - Pgsql_IResult.h \ - Pgsql_Params.h \ - Pgsql_PgException.h \ - Pgsql_Result.h \ - Pgsql_ResultConstIterator.h \ - Pgsql_Row.h \ - Pgsql_Value.h \ - Pgsql_declare.h \ - Pgsql_Col.h \ - ArrayParser.h \ - Pgsql_oids.h \ - SqlGenerator.h \ - Pgsql_Transaction.h \ - Pgsql_ErrorDetails.h \ - Pgsql_Canceller.h - - -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 += $$PWD/../core -DEPENDPATH += $$PWD/../core - -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/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..a02ee3c --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,5 @@ +find_package(GTest CONFIG REQUIRED) + +add_subdirectory(mygtestutils) +add_subdirectory(PgsqlTests) +add_subdirectory(pglabtests) diff --git a/tests/PgsqlTests/CMakeLists.txt b/tests/PgsqlTests/CMakeLists.txt new file mode 100644 index 0000000..34071a1 --- /dev/null +++ b/tests/PgsqlTests/CMakeLists.txt @@ -0,0 +1,24 @@ +add_executable(PgsqlTests + main.cpp + tst_Value.cpp + tst_ArrayParser.cpp + tst_Pgsql_oids.cpp + ) + +target_link_libraries(PgsqlTests PRIVATE + pgsql + mygtestutils + GTest::gtest + Qt6::Core + ) + +target_include_directories(PgsqlTests PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ) + +set_target_properties(PgsqlTests PROPERTIES + CXX_STANDARD 20 + CXX_STANDARD_REQUIRED ON + ) + +add_test(NAME PgsqlTests COMMAND PgsqlTests) diff --git a/tests/PgsqlTests/PgsqlTests.pro b/tests/PgsqlTests/PgsqlTests.pro deleted file mode 100644 index cb1d574..0000000 --- a/tests/PgsqlTests/PgsqlTests.pro +++ /dev/null @@ -1,46 +0,0 @@ -! include( ../../common.pri ) { -error( "Couldn't find the common.pri file!" ) -} -include(gtest_dependency.pri) - -TEMPLATE = app -CONFIG += console -CONFIG -= app_bundle -CONFIG += thread -CONFIG += qt - -QT += core - -HEADERS += - -SOURCES += main.cpp \ - tst_Value.cpp \ - tst_ArrayParser.cpp \ - tst_Pgsql_oids.cpp - - -win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../../pgsql/release/ -lpgsql -else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../../pgsql/debug/ -lpgsql -else:unix: LIBS += -L$$OUT_PWD/../../pgsql/ -lpgsql - -INCLUDEPATH += $$PWD/../../pgsql -DEPENDPATH += $$PWD/../../pgsql - -win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../pgsql/release/libpgsql.a -else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../pgsql/debug/libpgsql.a -else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../pgsql/release/pgsql.lib -else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../pgsql/debug/pgsql.lib -else:unix: PRE_TARGETDEPS += $$OUT_PWD/../../pgsql/libpgsql.a - -win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../mygtestutils/release/ -lmygtestutils -else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../mygtestutils/debug/ -lmygtestutils -else:unix:!macx: LIBS += -L$$OUT_PWD/../mygtestutils/ -lmygtestutils - -INCLUDEPATH += $$PWD/../mygtestutils -DEPENDPATH += $$PWD/../mygtestutils - -win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../mygtestutils/release/libmygtestutils.a -else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../mygtestutils/debug/libmygtestutils.a -else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../mygtestutils/release/mygtestutils.lib -else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../mygtestutils/debug/mygtestutils.lib -else:unix:!macx: PRE_TARGETDEPS += $$OUT_PWD/../mygtestutils/libmygtestutils.a diff --git a/tests/PgsqlTests/gtest_dependency.pri b/tests/PgsqlTests/gtest_dependency.pri deleted file mode 100644 index d01d7f0..0000000 --- a/tests/PgsqlTests/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/mygtestutils/CMakeLists.txt b/tests/mygtestutils/CMakeLists.txt new file mode 100644 index 0000000..930a0ad --- /dev/null +++ b/tests/mygtestutils/CMakeLists.txt @@ -0,0 +1,19 @@ +add_library(mygtestutils STATIC + PrintTo_Qt.cpp + PrintTo_Qt.h + ) + +target_link_libraries(mygtestutils PUBLIC + GTest::gtest + Qt6::Core + ) + +target_include_directories(mygtestutils PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ) + +set_target_properties(mygtestutils PROPERTIES + CXX_STANDARD 20 + CXX_STANDARD_REQUIRED ON + POSITION_INDEPENDENT_CODE ON + ) diff --git a/tests/mygtestutils/mygtestutils.pro b/tests/mygtestutils/mygtestutils.pro deleted file mode 100644 index a56a359..0000000 --- a/tests/mygtestutils/mygtestutils.pro +++ /dev/null @@ -1,32 +0,0 @@ -#------------------------------------------------- -# -# Project created by QtCreator 2017-12-01T10:07:31 -# -#------------------------------------------------- - -QT -= gui - -TARGET = mygtestutils -TEMPLATE = lib -CONFIG += staticlib - -# The following define makes your compiler emit warnings if you use -# any feature of Qt which has 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 += \ - PrintTo_Qt.cpp - -HEADERS += \ - PrintTo_Qt.h -unix { - target.path = /usr/lib - INSTALLS += target -} diff --git a/tests/pglabtests/CMakeLists.txt b/tests/pglabtests/CMakeLists.txt new file mode 100644 index 0000000..f13dc29 --- /dev/null +++ b/tests/pglabtests/CMakeLists.txt @@ -0,0 +1,41 @@ +add_executable(pglabtests + main.cpp + TableTreeBuilderTests.cpp + tst_ConvertLangToSqlString.cpp + tst_ConvertToMultiLineCString.cpp + tst_ExplainJsonParser.cpp + tst_HumanReadableBytes.cpp + tst_TryParsePostgresqlUrl.cpp + tst_escapeConnectionStringValue.cpp + tst_expected.cpp + tst_SqlLexer.cpp + tst_scopeguard.cpp + tst_CsvWriter.cpp + tst_PasswordManager.cpp + tst_ParamJson.cpp + tst_CodeBuilder.cpp + tst_NameManglingRules.cpp + tst_TypeMappings.cpp + tst_Range.cpp + ) + +target_link_libraries(pglabtests PRIVATE + pglablib + pgsql + core + mygtestutils + GTest::gtest + Qt6::Core + Qt6::Widgets + ) + +target_include_directories(pglabtests PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ) + +set_target_properties(pglabtests PROPERTIES + CXX_STANDARD 20 + CXX_STANDARD_REQUIRED ON + ) + +add_test(NAME pglabtests COMMAND pglabtests) diff --git a/tests/pglabtests/pglabtests.pro b/tests/pglabtests/pglabtests.pro deleted file mode 100644 index a666430..0000000 --- a/tests/pglabtests/pglabtests.pro +++ /dev/null @@ -1,86 +0,0 @@ -! include( ../../common.pri ) { -error( "Couldn't find the common.pri file!" ) -} -include(gtest_dependency.pri) - -TEMPLATE = app -CONFIG += console -CONFIG -= app_bundle -CONFIG += thread -CONFIG += qt - -QT += core widgets - -HEADERS += - -SOURCES += main.cpp \ - TableTreeBuilderTests.cpp \ - tst_ConvertLangToSqlString.cpp \ - tst_ConvertToMultiLineCString.cpp \ - tst_ExplainJsonParser.cpp \ - tst_HumanReadableBytes.cpp \ - tst_TryParsePostgresqlUrl.cpp \ - tst_escapeConnectionStringValue.cpp \ - tst_expected.cpp \ - tst_SqlLexer.cpp \ - tst_scopeguard.cpp \ - tst_CsvWriter.cpp \ - tst_PasswordManager.cpp \ - tst_ParamJson.cpp \ - tst_CodeBuilder.cpp \ - tst_NameManglingRules.cpp \ - tst_TypeMappings.cpp \ - tst_Range.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 += $$PWD/../../core -DEPENDPATH += $$PWD/../../core - -win32:CONFIG(debug, debug|release): LIBS += -lbotand -else:win32:CONFIG(release, debug|release): LIBS += -lbotan - -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 - -win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../../pgsql/release/ -lpgsql -else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../../pgsql/debug/ -lpgsql -else:unix:!macx: LIBS += -L$$OUT_PWD/../../pgsql/ -lpgsql - -INCLUDEPATH += $$PWD/../../pgsql -DEPENDPATH += $$PWD/../../pgsql - -win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../pgsql/release/libpgsql.a -else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../pgsql/debug/libpgsql.a -else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../pgsql/release/pgsql.lib -else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../pgsql/debug/pgsql.lib -else:unix:!macx: PRE_TARGETDEPS += $$OUT_PWD/../../pgsql/libpgsql.a - -win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../../pglablib/release/ -lpglablib -else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../../pglablib/debug/ -lpglablib -else:unix:!macx: LIBS += -L$$OUT_PWD/../../pglablib/ -lpglablib - -INCLUDEPATH += $$PWD/../../pglablib -DEPENDPATH += $$PWD/../../pglablib - -win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../pglablib/release/libpglablib.a -else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../pglablib/debug/libpglablib.a -else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../pglablib/release/pglablib.lib -else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../pglablib/debug/pglablib.lib -else:unix:!macx: PRE_TARGETDEPS += $$OUT_PWD/../../pglablib/libpglablib.a - -win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../mygtestutils/release/ -lmygtestutils -else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../mygtestutils/debug/ -lmygtestutils -else:unix:!macx: LIBS += -L$$OUT_PWD/../mygtestutils/ -lmygtestutils - -INCLUDEPATH += $$PWD/../mygtestutils -DEPENDPATH += $$PWD/../mygtestutils - -win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../mygtestutils/release/libmygtestutils.a -else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../mygtestutils/debug/libmygtestutils.a -else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../mygtestutils/release/mygtestutils.lib -else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../mygtestutils/debug/mygtestutils.lib -else:unix:!macx: PRE_TARGETDEPS += $$OUT_PWD/../mygtestutils/libmygtestutils.a diff --git a/tests/tests.pro b/tests/tests.pro deleted file mode 100644 index ee23c08..0000000 --- a/tests/tests.pro +++ /dev/null @@ -1,5 +0,0 @@ -TEMPLATE = subdirs - -SUBDIRS += PgsqlTests \ - pglabtests \ - mygtestutils diff --git a/vcpkg.json b/vcpkg.json new file mode 100644 index 0000000..4283df6 --- /dev/null +++ b/vcpkg.json @@ -0,0 +1,13 @@ +{ + "name": "pglab", + "version-string": "0.1.0", + "dependencies": [ + "boost-container", + "boost-timer", + "boost-chrono", + "boost-assert", + "botan", + "libpq", + "gtest" + ] +}