port from mysql conenctor to QTSQL module
add new classes to manage connections begin work on generic database for client and db
This commit is contained in:
24
.gitignore
vendored
24
.gitignore
vendored
@@ -1,18 +1,6 @@
|
|||||||
/**
|
/out
|
||||||
!/bin/**
|
/bin
|
||||||
!/cmake/**
|
/build
|
||||||
!/etc/**
|
/.vs
|
||||||
!/include/**
|
/CMakePresets.json
|
||||||
!/media/**
|
/CMakeUserPresets.json
|
||||||
!/resources/**
|
|
||||||
!/sql/**
|
|
||||||
!/src/**
|
|
||||||
!/test/**
|
|
||||||
!/.idea/**
|
|
||||||
!.gitignore
|
|
||||||
!.CMakeLists.txt
|
|
||||||
!COPYING
|
|
||||||
!Doxyfile
|
|
||||||
!README.md
|
|
||||||
!todo_1.4.md
|
|
||||||
!uid_fix_concept.md
|
|
||||||
108
CMakeLists.txt
108
CMakeLists.txt
@@ -88,7 +88,6 @@ SET(LIBARY_OUTPUT_PATH bin)
|
|||||||
SET(EXTERNAL_SOURCE_DIR src/external)
|
SET(EXTERNAL_SOURCE_DIR src/external)
|
||||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||||
|
|
||||||
# OPTION(USE_SQL "Enable sql uid save ? (require mysql installed)" OFF)
|
|
||||||
OPTION(VALIDATE_OPENGL_PROGRAMS "Validate Opengl programs" OFF)
|
OPTION(VALIDATE_OPENGL_PROGRAMS "Validate Opengl programs" OFF)
|
||||||
|
|
||||||
IF(VALIDATE_OPENGL_PROGRAMS)
|
IF(VALIDATE_OPENGL_PROGRAMS)
|
||||||
@@ -115,32 +114,7 @@ FetchContent_Declare(
|
|||||||
FetchContent_MakeAvailable(FastNoise2)
|
FetchContent_MakeAvailable(FastNoise2)
|
||||||
|
|
||||||
FIND_PACKAGE(Sol2 REQUIRED)
|
FIND_PACKAGE(Sol2 REQUIRED)
|
||||||
FIND_PACKAGE(Qt5 COMPONENTS Widgets OpenGLExtensions Gui Network Xml Multimedia REQUIRED)
|
FIND_PACKAGE(Qt5 COMPONENTS Widgets OpenGLExtensions Gui Network Xml Multimedia Sql REQUIRED)
|
||||||
|
|
||||||
# IF(USE_SQL)
|
|
||||||
FIND_LIBRARY(MYSQL_LIBRARY NAMES libmysql
|
|
||||||
HINTS "${CMAKE_SOURCE_DIR}/../Noggit3libs/mysql")
|
|
||||||
FIND_LIBRARY(MYSQLCPPCONN_LIBRARY NAMES mysqlcppconn
|
|
||||||
HINTS "${CMAKE_SOURCE_DIR}/../Noggit3libs/mysql/connector")
|
|
||||||
FIND_PATH(MYSQLCPPCONN_INCLUDE NAMES cppconn/driver.h
|
|
||||||
HINTS "${CMAKE_SOURCE_DIR}/../Noggit3libs/mysql/connector")
|
|
||||||
|
|
||||||
# Ensure we always include the parent of 'cppconn' folder
|
|
||||||
if(EXISTS "${MYSQLCPPCONN_INCLUDE}/cppconn")
|
|
||||||
set(MYSQLCPPCONN_INCLUDE "${MYSQLCPPCONN_INCLUDE}")
|
|
||||||
elseif(EXISTS "${MYSQLCPPCONN_INCLUDE}/driver.h")
|
|
||||||
get_filename_component(MYSQLCPPCONN_INCLUDE "${MYSQLCPPCONN_INCLUDE}" DIRECTORY)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
IF(MYSQL_LIBRARY AND MYSQLCPPCONN_LIBRARY AND MYSQLCPPCONN_INCLUDE)
|
|
||||||
ADD_DEFINITIONS(-DUSE_MYSQL_UID_STORAGE)
|
|
||||||
SET (mysql_sources src/mysql/mysql.cpp)
|
|
||||||
SET (mysql_headers src/mysql/mysql.h)
|
|
||||||
SOURCE_GROUP("mysql" FILES ${mysql_sources} ${mysql_headers})
|
|
||||||
ELSE()
|
|
||||||
MESSAGE(FATAL_ERROR "MySQL lib or connector not found")
|
|
||||||
ENDIF()
|
|
||||||
# ENDIF()
|
|
||||||
|
|
||||||
ADD_SUBDIRECTORY("${EXTERNAL_SOURCE_DIR}/qt-color-widgets")
|
ADD_SUBDIRECTORY("${EXTERNAL_SOURCE_DIR}/qt-color-widgets")
|
||||||
ADD_SUBDIRECTORY("${EXTERNAL_SOURCE_DIR}/framelesshelper")
|
ADD_SUBDIRECTORY("${EXTERNAL_SOURCE_DIR}/framelesshelper")
|
||||||
@@ -297,7 +271,6 @@ ADD_EXECUTABLE(noggit
|
|||||||
${opengl_sources}
|
${opengl_sources}
|
||||||
${math_sources}
|
${math_sources}
|
||||||
${external_sources}
|
${external_sources}
|
||||||
${mysql_sources}
|
|
||||||
${os_sources}
|
${os_sources}
|
||||||
${util_sources}
|
${util_sources}
|
||||||
${util_headers}
|
${util_headers}
|
||||||
@@ -311,7 +284,6 @@ ADD_EXECUTABLE(noggit
|
|||||||
${opengl_headers}
|
${opengl_headers}
|
||||||
${math_headers}
|
${math_headers}
|
||||||
${external_headers}
|
${external_headers}
|
||||||
${mysql_headers}
|
|
||||||
${os_headers}
|
${os_headers}
|
||||||
${png_blp_headers}
|
${png_blp_headers}
|
||||||
${ResFiles}
|
${ResFiles}
|
||||||
@@ -355,6 +327,7 @@ TARGET_LINK_LIBRARIES (noggit
|
|||||||
Qt5::Xml
|
Qt5::Xml
|
||||||
Qt5::Network
|
Qt5::Network
|
||||||
Qt5::Multimedia
|
Qt5::Multimedia
|
||||||
|
Qt5::Sql
|
||||||
ColorWidgets-qt5
|
ColorWidgets-qt5
|
||||||
FramelessHelper
|
FramelessHelper
|
||||||
qt_imgui_widgets
|
qt_imgui_widgets
|
||||||
@@ -371,6 +344,78 @@ TARGET_LINK_LIBRARIES (noggit
|
|||||||
blizzard-database-library
|
blizzard-database-library
|
||||||
rapidfuzz::rapidfuzz
|
rapidfuzz::rapidfuzz
|
||||||
)
|
)
|
||||||
|
include(ExternalProject)
|
||||||
|
|
||||||
|
|
||||||
|
# Fetch qsqlmysql.dll plugin based on Qt version #####
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${Qt5Core_DIR}/../../../bin/qmake -query QT_VERSION
|
||||||
|
OUTPUT_VARIABLE QT_FULL_VERSION
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
)
|
||||||
|
message(STATUS "Qt full version: ${QT_FULL_VERSION}")
|
||||||
|
|
||||||
|
# prebuilds available at : https://github.com/thecodemonkey86/qt_mysql_driver/releases
|
||||||
|
# get direct download links
|
||||||
|
if(WIN32)
|
||||||
|
if(MSVC)
|
||||||
|
set(QMYSQL_PREBUILT_DRIVER_URL
|
||||||
|
"https://github.com/thecodemonkey86/qt_mysql_driver/files/5575770/qsqlmysql.dll_Qt_SQL_driver_${QT_FULL_VERSION}_MSVC2019_64-bit.zip"
|
||||||
|
)
|
||||||
|
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") # MinGW
|
||||||
|
set(QMYSQL_PREBUILT_DRIVER_URL
|
||||||
|
"https://github.com/thecodemonkey86/qt_mysql_driver/files/5575769/qsqlmysql.dll_Qt_SQL_driver_${QT_FULL_VERSION}_MinGW_8.1.0_64-bit.zip"
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
message(WARNING "Unsupported Windows compiler for prebuilt MySQL Qt driver")
|
||||||
|
endif()
|
||||||
|
elseif(UNIX)
|
||||||
|
set(QMYSQL_PREBUILT_DRIVER_URL
|
||||||
|
"https://github.com/thecodemonkey86/qt_mysql_driver/files/6388052/libqsqlmysql.so_Qt_SQL_driver_${QT_FULL_VERSION}_gcc64.zip"
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
message(WARNING "Unsupported platform for prebuilt MySQL Qt driver")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(QMYSQL_PREBUILT_DIR "${CMAKE_BINARY_DIR}/_deps/qt_mysql_driver")
|
||||||
|
set(QMYSQL_EXTRACT_DIR "${QMYSQL_PREBUILT_DIR}/sqldrivers")
|
||||||
|
set(QMYSQL_ZIP "${QMYSQL_PREBUILT_DIR}/qsqlmysql_prebuilt.zip")
|
||||||
|
|
||||||
|
# Download zip only if not already present
|
||||||
|
if(NOT EXISTS "${QMYSQL_ZIP}")
|
||||||
|
message(STATUS "qt MySQL DRIVER zip not found. Downloading qmysql from : ${QMYSQL_PREBUILT_DRIVER_URL}")
|
||||||
|
|
||||||
|
file(DOWNLOAD
|
||||||
|
${QMYSQL_PREBUILT_DRIVER_URL}
|
||||||
|
${QMYSQL_ZIP}
|
||||||
|
# SHOW_PROGRESS
|
||||||
|
STATUS DOWNLOAD_STATUS
|
||||||
|
TLS_VERIFY ON
|
||||||
|
)
|
||||||
|
|
||||||
|
list(GET DOWNLOAD_STATUS 0 STATUS_CODE)
|
||||||
|
if(NOT STATUS_CODE EQUAL 0)
|
||||||
|
message(WARNING "Failed to download prebuilt qt MySQL driver: ${DOWNLOAD_STATUS}")
|
||||||
|
message(WARNING "You can manually download it from https://github.com/thecodemonkey86/qt_mysql_driver/releases or build qsqlmysql.dll yourself from QT source.")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
message(STATUS "Prebuilt MySQL Qt driver zip already exists, skipping download")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Extract zip
|
||||||
|
file(ARCHIVE_EXTRACT
|
||||||
|
INPUT ${QMYSQL_ZIP}
|
||||||
|
DESTINATION ${QMYSQL_EXTRACT_DIR}
|
||||||
|
)
|
||||||
|
message(STATUS "Extracted prebuilt MySQL Qt driver at ${QMYSQL_EXTRACT_DIR}. Deps will be deploeyd after build.")
|
||||||
|
|
||||||
|
|
||||||
|
# deploy
|
||||||
|
add_custom_command(TARGET noggit POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||||
|
"${QMYSQL_EXTRACT_DIR}"
|
||||||
|
"$<TARGET_FILE_DIR:noggit>"
|
||||||
|
)
|
||||||
|
|
||||||
#add distribution themes
|
#add distribution themes
|
||||||
add_custom_command(TARGET noggit POST_BUILD
|
add_custom_command(TARGET noggit POST_BUILD
|
||||||
@@ -452,11 +497,6 @@ IF(APPLE)
|
|||||||
TARGET_LINK_LIBRARIES (noggit "-framework Cocoa" "-framework AppKit" "-framework Foundation")
|
TARGET_LINK_LIBRARIES (noggit "-framework Cocoa" "-framework AppKit" "-framework Foundation")
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
IF(MYSQL_LIBRARY AND MYSQLCPPCONN_LIBRARY AND MYSQLCPPCONN_INCLUDE)
|
|
||||||
TARGET_LINK_LIBRARIES(noggit ${MYSQL_LIBRARY} ${MYSQLCPPCONN_LIBRARY})
|
|
||||||
TARGET_INCLUDE_DIRECTORIES(noggit SYSTEM PRIVATE ${MYSQLCPPCONN_INCLUDE})
|
|
||||||
ENDIF()
|
|
||||||
|
|
||||||
IF(NOGGIT_LOGTOCONSOLE AND WIN32)
|
IF(NOGGIT_LOGTOCONSOLE AND WIN32)
|
||||||
SET_PROPERTY(TARGET noggit APPEND PROPERTY LINK_FLAGS_DEBUG "/SUBSYSTEM:CONSOLE")
|
SET_PROPERTY(TARGET noggit APPEND PROPERTY LINK_FLAGS_DEBUG "/SUBSYSTEM:CONSOLE")
|
||||||
SET_PROPERTY(TARGET noggit APPEND PROPERTY COMPILE_DEFINITIONS $<$<CONFIG:Debug>:"_CONSOLE">)
|
SET_PROPERTY(TARGET noggit APPEND PROPERTY COMPILE_DEFINITIONS $<$<CONFIG:Debug>:"_CONSOLE">)
|
||||||
|
|||||||
2
src/external/blizzard-database-library
vendored
2
src/external/blizzard-database-library
vendored
Submodule src/external/blizzard-database-library updated: d0b399cb52...1cefbe958a
@@ -1,166 +0,0 @@
|
|||||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
|
||||||
|
|
||||||
#include <mysql/mysql.h>
|
|
||||||
#include <noggit/world.h>
|
|
||||||
|
|
||||||
#include <QSettings>
|
|
||||||
#include <QMessageBox>
|
|
||||||
|
|
||||||
#include <cppconn/driver.h>
|
|
||||||
#include <cppconn/prepared_statement.h>
|
|
||||||
#include <cppconn/exception.h>
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
std::unique_ptr<sql::Connection> connect()
|
|
||||||
{
|
|
||||||
QSettings settings;
|
|
||||||
|
|
||||||
// if using release SQL binaries in debug mode it will crash https://bugs.mysql.com/bug.php?id=91238 unless using sql strings
|
|
||||||
// tcp://127.0.0.1:3306
|
|
||||||
const sql::SQLString hostname = "tcp://" + settings.value("project/mysql/server").toString().toStdString() + ":" + settings.value("project/mysql/port", "3306").toString().toStdString();
|
|
||||||
const sql::SQLString userName = settings.value("project/mysql/user").toString().toStdString();
|
|
||||||
const sql::SQLString password = settings.value("project/mysql/pwd").toString().toStdString();
|
|
||||||
const sql::SQLString schema = settings.value("project/mysql/db").toString().toStdString();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
std::unique_ptr<sql::Connection> Con(get_driver_instance()->connect(hostname, userName, password));
|
|
||||||
|
|
||||||
// crete database if it doesn't exist
|
|
||||||
std::string createdb_statement = "CREATE DATABASE IF NOT EXISTS " + schema;
|
|
||||||
std::unique_ptr<sql::PreparedStatement> dbpstmt(Con->prepareStatement(createdb_statement));
|
|
||||||
std::unique_ptr<sql::ResultSet> res(dbpstmt->executeQuery());
|
|
||||||
|
|
||||||
Con->setSchema(schema);
|
|
||||||
|
|
||||||
// create table if it doesn't exist, querries from src/sql
|
|
||||||
std::unique_ptr<sql::PreparedStatement> tablepstmt(Con->prepareStatement("CREATE TABLE IF NOT EXISTS `UIDs` ("
|
|
||||||
"`_map_id` int(11) NOT NULL,"
|
|
||||||
"`UID` int(11) NOT NULL,"
|
|
||||||
"PRIMARY KEY(`_map_id`)"
|
|
||||||
") ENGINE = InnoDB DEFAULT CHARSET = latin1;"));
|
|
||||||
std::unique_ptr<sql::ResultSet> tableres(tablepstmt->executeQuery());
|
|
||||||
|
|
||||||
return Con;
|
|
||||||
}
|
|
||||||
catch (sql::SQLException& e)
|
|
||||||
{
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
catch (std::exception& e)
|
|
||||||
{
|
|
||||||
std::cerr << "SQL Other exception: " << e.what() << std::endl;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace mysql
|
|
||||||
{
|
|
||||||
bool testConnection(bool report_only_err)
|
|
||||||
{
|
|
||||||
QSettings settings;
|
|
||||||
// if using release SQL binaries in debug mode it will crash https://bugs.mysql.com/bug.php?id=91238 unless using sql strings
|
|
||||||
const sql::SQLString hostname = "tcp://" + settings.value("project/mysql/server").toString().toStdString() + ":" + settings.value("project/mysql/port", "3306").toString().toStdString();
|
|
||||||
const sql::SQLString userName = settings.value("project/mysql/user").toString().toStdString();
|
|
||||||
const sql::SQLString password = settings.value("project/mysql/pwd").toString().toStdString();
|
|
||||||
|
|
||||||
QMessageBox prompt;
|
|
||||||
prompt.setWindowFlag(Qt::WindowStaysOnTopHint);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
sql::Driver* driver = get_driver_instance();
|
|
||||||
sql::Connection* connection = driver->connect(hostname, userName, password);
|
|
||||||
std::unique_ptr<sql::Connection> Con(connection);
|
|
||||||
|
|
||||||
prompt.setIcon(QMessageBox::Information);
|
|
||||||
prompt.setText("Succesfully connected to MySQL database.");
|
|
||||||
prompt.setWindowTitle("Success");
|
|
||||||
|
|
||||||
if (!report_only_err)
|
|
||||||
prompt.exec();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (sql::SQLException& e)
|
|
||||||
{
|
|
||||||
|
|
||||||
prompt.setIcon(QMessageBox::Warning);
|
|
||||||
prompt.setText("Failed to load MySQL database, check your settings. \nIf you did not intend to use this feature, disable it in Noggit->settings->MySQL");
|
|
||||||
prompt.setWindowTitle("Noggit Database Error");
|
|
||||||
// disable if connection is not valid
|
|
||||||
// settings.value("project/mysql/enabled") = false;
|
|
||||||
std::stringstream promptText;
|
|
||||||
|
|
||||||
promptText << "\n# ERR: " << e.what();
|
|
||||||
promptText << "\n (MySQL error code: " << e.getErrorCode() + ")";
|
|
||||||
|
|
||||||
prompt.setInformativeText(promptText.str().c_str());
|
|
||||||
prompt.exec();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
catch (std::exception& e)
|
|
||||||
{
|
|
||||||
std::cerr << "SQL Other exception: " << e.what() << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasMaxUIDStoredDB(std::size_t mapID)
|
|
||||||
{
|
|
||||||
auto Con(connect());
|
|
||||||
if (Con == nullptr)
|
|
||||||
return false;
|
|
||||||
std::unique_ptr<sql::PreparedStatement> pstmt(Con->prepareStatement("SELECT * FROM `UIDs` WHERE `_map_id`=(?)"));
|
|
||||||
pstmt->setInt(1, mapID);
|
|
||||||
std::unique_ptr<sql::ResultSet> res(pstmt->executeQuery());
|
|
||||||
return res->rowsCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::uint32_t getGUIDFromDB(std::size_t mapID)
|
|
||||||
{
|
|
||||||
auto Con(connect());
|
|
||||||
if (Con == nullptr)
|
|
||||||
return 0;
|
|
||||||
std::unique_ptr<sql::PreparedStatement> pstmt(Con->prepareStatement("SELECT `UID` FROM `UIDs` WHERE `_map_id`=(?)"));
|
|
||||||
pstmt->setInt(1, mapID);
|
|
||||||
std::unique_ptr<sql::ResultSet> res(pstmt->executeQuery());
|
|
||||||
|
|
||||||
std::uint32_t highGUID(0);
|
|
||||||
if (res->rowsCount() == 0)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
while (res->next())
|
|
||||||
{
|
|
||||||
highGUID = res->getInt(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return highGUID;
|
|
||||||
}
|
|
||||||
|
|
||||||
void insertUIDinDB(std::size_t mapID, std::uint32_t NewUID)
|
|
||||||
{
|
|
||||||
auto Con(connect());
|
|
||||||
if (Con == nullptr)
|
|
||||||
return;
|
|
||||||
std::unique_ptr<sql::PreparedStatement> pstmt(Con->prepareStatement("INSERT INTO `UIDs` SET `_map_id`=(?), `UID`=(?)"));
|
|
||||||
pstmt->setInt(1, mapID);
|
|
||||||
pstmt->setInt(2, NewUID);
|
|
||||||
pstmt->executeUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateUIDinDB (std::size_t mapID, std::uint32_t NewUID)
|
|
||||||
{
|
|
||||||
auto Con(connect());
|
|
||||||
if (Con == nullptr)
|
|
||||||
return;
|
|
||||||
std::unique_ptr<sql::PreparedStatement> pstmt(Con->prepareStatement("UPDATE `UIDs` SET `UID`=(?) WHERE `_map_id`=(?)"));
|
|
||||||
pstmt->setInt(1, NewUID);
|
|
||||||
pstmt->setInt(2, mapID);
|
|
||||||
pstmt->executeUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cinttypes>
|
|
||||||
#include <cstddef>
|
|
||||||
|
|
||||||
namespace mysql
|
|
||||||
{
|
|
||||||
bool testConnection(bool report_only_err = false);
|
|
||||||
bool hasMaxUIDStoredDB(std::size_t mapID);
|
|
||||||
std::uint32_t getGUIDFromDB(std::size_t mapID);
|
|
||||||
void insertUIDinDB(std::size_t mapID, std::uint32_t NewUID);
|
|
||||||
void updateUIDinDB (std::size_t mapID, std::uint32_t NewUID);
|
|
||||||
};
|
|
||||||
@@ -76,11 +76,8 @@
|
|||||||
#include <noggit/tools/AreaTriggerTool.hpp>
|
#include <noggit/tools/AreaTriggerTool.hpp>
|
||||||
#include <noggit/StringHash.hpp>
|
#include <noggit/StringHash.hpp>
|
||||||
#include <noggit/application/NoggitApplication.hpp>
|
#include <noggit/application/NoggitApplication.hpp>
|
||||||
|
#include <noggit/sql/DatabaseManager.h>
|
||||||
|
|
||||||
#ifdef USE_MYSQL_UID_STORAGE
|
|
||||||
#include <mysql/mysql.h>
|
|
||||||
|
|
||||||
#endif
|
|
||||||
#include <QtCore/QSettings>
|
#include <QtCore/QSettings>
|
||||||
|
|
||||||
#include <noggit/scripting/scripting_tool.hpp>
|
#include <noggit/scripting/scripting_tool.hpp>
|
||||||
@@ -2472,17 +2469,23 @@ void MapView::createGUI()
|
|||||||
set_editing_mode (editing_mode::ground);
|
set_editing_mode (editing_mode::ground);
|
||||||
|
|
||||||
// do we need to do this every tick ?
|
// do we need to do this every tick ?
|
||||||
#ifdef USE_MYSQL_UID_STORAGE
|
|
||||||
if (_settings->value("project/mysql/enabled").toBool())
|
if (_settings->value("project/mysql/enabled").toBool())
|
||||||
{
|
{
|
||||||
if (mysql::hasMaxUIDStoredDB(_world->getMapID()))
|
auto& db_mgr = Noggit::Sql::DatabaseManager::instance();
|
||||||
|
|
||||||
|
if (db_mgr.testConnection(Noggit::Sql::SQLDbType::Noggit))
|
||||||
{
|
{
|
||||||
_status_database->setText("MySQL UID sync enabled: "
|
_status_database->setText("UID SQL Database is active: "
|
||||||
|
+ _settings->value("project/mysql/server").toString() + ":"
|
||||||
|
+ _settings->value("project/mysql/port").toString());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_status_database->setText("UID SQL Database is not working: "
|
||||||
+ _settings->value("project/mysql/server").toString() + ":"
|
+ _settings->value("project/mysql/server").toString() + ":"
|
||||||
+ _settings->value("project/mysql/port").toString());
|
+ _settings->value("project/mysql/port").toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapView::on_exit_prompt()
|
void MapView::on_exit_prompt()
|
||||||
|
|||||||
@@ -9,13 +9,11 @@
|
|||||||
#include <noggit/ActionManager.hpp>
|
#include <noggit/ActionManager.hpp>
|
||||||
#include <noggit/Action.hpp>
|
#include <noggit/Action.hpp>
|
||||||
#include <noggit/project/CurrentProject.hpp>
|
#include <noggit/project/CurrentProject.hpp>
|
||||||
#ifdef USE_MYSQL_UID_STORAGE
|
|
||||||
#include <mysql/mysql.h>
|
|
||||||
#endif
|
|
||||||
#include <noggit/map_index.hpp>
|
#include <noggit/map_index.hpp>
|
||||||
#include <noggit/uid_storage.hpp>
|
#include <noggit/uid_storage.hpp>
|
||||||
#include <noggit/application/NoggitApplication.hpp>
|
#include <noggit/application/NoggitApplication.hpp>
|
||||||
#include <ClientFile.hpp>
|
#include <ClientFile.hpp>
|
||||||
|
#include <noggit/sql/SqlUIDStorage.h>
|
||||||
|
|
||||||
#include <QtCore/QSettings>
|
#include <QtCore/QSettings>
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
@@ -776,14 +774,13 @@ uint32_t MapIndex::newGUID()
|
|||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock (_mutex);
|
std::unique_lock<std::mutex> lock (_mutex);
|
||||||
|
|
||||||
#ifdef USE_MYSQL_UID_STORAGE
|
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
|
|
||||||
if (settings.value ("project/mysql/enabled", false).toBool())
|
if (settings.value ("project/mysql/enabled", false).toBool())
|
||||||
{
|
{
|
||||||
mysql::updateUIDinDB(_map_id, highestGUID + 1); // update the highest uid in db, note that if the user don't save these uid won't be used (not really a problem tho)
|
// update the highest uid in db, note that if the user don't save these uid won't be used (not really a problem tho)
|
||||||
|
Noggit::Sql::SqlUIDStorage::updateUIDinDB(_map_id, highestGUID + 1);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
return ++highestGUID;
|
return ++highestGUID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1135,21 +1132,19 @@ void MapIndex::searchMaxUID()
|
|||||||
|
|
||||||
void MapIndex::saveMaxUID()
|
void MapIndex::saveMaxUID()
|
||||||
{
|
{
|
||||||
#ifdef USE_MYSQL_UID_STORAGE
|
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
|
|
||||||
if (settings.value ("project/mysql/enabled", false).toBool())
|
if (settings.value ("project/mysql/enabled", false).toBool())
|
||||||
{
|
{
|
||||||
if (mysql::hasMaxUIDStoredDB(_map_id))
|
if (Noggit::Sql::SqlUIDStorage::hasMaxUIDStoredDB(_map_id))
|
||||||
{
|
{
|
||||||
mysql::updateUIDinDB(_map_id, highestGUID);
|
Noggit::Sql::SqlUIDStorage::updateUIDinDB(_map_id, highestGUID);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mysql::insertUIDinDB(_map_id, highestGUID);
|
Noggit::Sql::SqlUIDStorage::insertUIDinDB(_map_id, highestGUID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
// save the max UID on the disk (always save to sync with the db if used
|
// save the max UID on the disk (always save to sync with the db if used
|
||||||
uid_storage::saveMaxUID (_map_id, highestGUID);
|
uid_storage::saveMaxUID (_map_id, highestGUID);
|
||||||
}
|
}
|
||||||
@@ -1157,16 +1152,14 @@ void MapIndex::saveMaxUID()
|
|||||||
void MapIndex::loadMaxUID()
|
void MapIndex::loadMaxUID()
|
||||||
{
|
{
|
||||||
highestGUID = uid_storage::getMaxUID (_map_id);
|
highestGUID = uid_storage::getMaxUID (_map_id);
|
||||||
#ifdef USE_MYSQL_UID_STORAGE
|
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
|
|
||||||
if (settings.value ("project/mysql/enabled", false).toBool())
|
if (settings.value ("project/mysql/enabled", false).toBool())
|
||||||
{
|
{
|
||||||
highestGUID = std::max(mysql::getGUIDFromDB(_map_id), highestGUID);
|
highestGUID = std::max(Noggit::Sql::SqlUIDStorage::getGUIDFromDB(_map_id), highestGUID);
|
||||||
// save to make sure the db and disk uid are synced
|
// save to make sure the db and disk uid are synced
|
||||||
saveMaxUID();
|
saveMaxUID();
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapIndex::loadMinimapMD5translate()
|
void MapIndex::loadMinimapMD5translate()
|
||||||
|
|||||||
@@ -259,6 +259,11 @@ namespace Noggit::Project
|
|||||||
_projectWriter = std::make_shared<ApplicationProjectWriter>();
|
_projectWriter = std::make_shared<ApplicationProjectWriter>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int NoggitProject::buildId()
|
||||||
|
{
|
||||||
|
return ClientDatabase->getBuild();
|
||||||
|
}
|
||||||
|
|
||||||
void NoggitProject::createBookmark(const NoggitProjectBookmarkMap& bookmark)
|
void NoggitProject::createBookmark(const NoggitProjectBookmarkMap& bookmark)
|
||||||
{
|
{
|
||||||
Bookmarks.push_back(bookmark);
|
Bookmarks.push_back(bookmark);
|
||||||
|
|||||||
@@ -117,6 +117,8 @@ namespace Noggit::Project
|
|||||||
NoggitExtraMapData ExtraMapData;
|
NoggitExtraMapData ExtraMapData;
|
||||||
NoggitProject();
|
NoggitProject();
|
||||||
|
|
||||||
|
unsigned int buildId();
|
||||||
|
|
||||||
void createBookmark(const NoggitProjectBookmarkMap& bookmark);
|
void createBookmark(const NoggitProjectBookmarkMap& bookmark);
|
||||||
|
|
||||||
void deleteBookmark();
|
void deleteBookmark();
|
||||||
|
|||||||
540
src/noggit/sql/ClientDatabase.cpp
Normal file
540
src/noggit/sql/ClientDatabase.cpp
Normal file
@@ -0,0 +1,540 @@
|
|||||||
|
#include "ClientDatabase.h"
|
||||||
|
#include <noggit/project/CurrentProject.hpp>
|
||||||
|
#include <noggit/application/Utils.hpp>
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <QSqlRecord>
|
||||||
|
#include <QSqlField>
|
||||||
|
#include <QElapsedTimer>
|
||||||
|
|
||||||
|
namespace Noggit
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
std::optional<Structures::BlizzardDatabaseRow> ClientDatabase::getRowById(const std::string& tableName, unsigned int id)
|
||||||
|
{
|
||||||
|
bool setting_use_sql_db = false; // todo QSETTING
|
||||||
|
|
||||||
|
auto row = Structures::BlizzardDatabaseRow(-1);
|
||||||
|
|
||||||
|
if (setting_use_sql_db)
|
||||||
|
row = sqlRowById(tableName, id);
|
||||||
|
else
|
||||||
|
row = clientRowById(tableName, id);
|
||||||
|
|
||||||
|
if (row.RecordId == -1)
|
||||||
|
return std::nullopt;
|
||||||
|
else
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClientDatabase::testUploadDBCtoDB(BlizzardDatabaseLib::BlizzardDatabaseTable& table)
|
||||||
|
{
|
||||||
|
|
||||||
|
auto& db_mgr = Noggit::Sql::DatabaseManager::instance();
|
||||||
|
bool valid_conn = db_mgr.testConnection(Noggit::Sql::SQLDbType::Noggit);
|
||||||
|
if (!valid_conn)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto table_name = table.Name();
|
||||||
|
// Noggit::Project::CurrentProject::get()->projectVersion; // expension, not exact build id
|
||||||
|
unsigned int build_id = Noggit::Project::CurrentProject::get()->buildId();
|
||||||
|
|
||||||
|
// check if table exists
|
||||||
|
QString sql_table_name = getSqlTableName(table_name, build_id).c_str();
|
||||||
|
|
||||||
|
auto noggit_db = db_mgr.noggitDatabase();
|
||||||
|
|
||||||
|
// table integrity check
|
||||||
|
bool table_is_valid = true;
|
||||||
|
bool fresh_table = false;
|
||||||
|
QSqlRecord sql_rec = noggit_db.record(sql_table_name);
|
||||||
|
|
||||||
|
// noggit_db.tables().contains(sql_table_name) is bugged with current qt version and mysql 8
|
||||||
|
QSqlQuery query_show(noggit_db);
|
||||||
|
if (!query_show.exec("SHOW TABLES"))
|
||||||
|
{
|
||||||
|
qWarning() << "Failed to list tables:" << query_show.lastError().text();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
QStringList tables;
|
||||||
|
while (query_show.next())
|
||||||
|
{
|
||||||
|
tables << query_show.value(0).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tables.contains(sql_table_name))
|
||||||
|
{
|
||||||
|
// this is also bugged...
|
||||||
|
// if (sql_rec.isEmpty())
|
||||||
|
// {
|
||||||
|
// table_is_valid = false;
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// // TODO verify db structure, just column count for now
|
||||||
|
// if (table.ColumnCount() != sql_rec.count())
|
||||||
|
// {
|
||||||
|
// assert(false);
|
||||||
|
// table_is_valid = false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
else // table doesn't exist
|
||||||
|
{
|
||||||
|
// create table
|
||||||
|
table_is_valid = createSQLTableIfNotExist(table);
|
||||||
|
fresh_table = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!table_is_valid)
|
||||||
|
{
|
||||||
|
qDebug() << "Table " << sql_table_name << "does not exist or has wrong structure.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert if fresh_table, otherwise replace?
|
||||||
|
|
||||||
|
// TODOOOOOOOOOOOOOOOOOOOOOOO : fill db with data
|
||||||
|
auto row_definition = table.GetRecordDefinition();
|
||||||
|
auto sql_record_format = recordFormat(table_name);
|
||||||
|
|
||||||
|
auto client_table_iterator = table.Records();
|
||||||
|
|
||||||
|
QStringList column_names;
|
||||||
|
for (auto& sql_column_format : sql_record_format)
|
||||||
|
{
|
||||||
|
column_names.append(sql_column_format.Name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// INSERT INTO table (col1, col2, ...) VALUES (?, ?, ...)
|
||||||
|
QString sql = QString("INSERT INTO `%1` (%2) VALUES (%3)")
|
||||||
|
.arg(sql_table_name)
|
||||||
|
.arg(column_names.join(", "))
|
||||||
|
.arg(QString("?, ").repeated(column_names.size()).chopped(2));
|
||||||
|
|
||||||
|
QSqlQuery query(noggit_db);
|
||||||
|
if (!query.prepare(sql))
|
||||||
|
{
|
||||||
|
qWarning() << "Prepare failed:" << query.lastError().text();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QElapsedTimer timer;
|
||||||
|
timer.start();
|
||||||
|
|
||||||
|
// using transaction to speed up bulk query
|
||||||
|
// noggit_db.transaction();
|
||||||
|
|
||||||
|
// batching:
|
||||||
|
// One QVariantList per column
|
||||||
|
std::vector<QVariantList> columnData(column_names.size());
|
||||||
|
|
||||||
|
while (client_table_iterator.HasRecords())
|
||||||
|
{
|
||||||
|
auto& record = client_table_iterator.Next();
|
||||||
|
int colIndex = 0;
|
||||||
|
|
||||||
|
for (auto& column_def : row_definition.ColumnDefinitions)
|
||||||
|
{
|
||||||
|
if (column_def.Type == "int" && column_def.isID) // id column isn't saved in the map
|
||||||
|
{
|
||||||
|
// query.addBindValue(record.RecordId);
|
||||||
|
columnData[colIndex++].append(record.RecordId); // batching
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& rowColumn = record.Columns.at(column_def.Name);
|
||||||
|
|
||||||
|
if (column_def.Type == "int")
|
||||||
|
{
|
||||||
|
if (column_def.arrLength > 1)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < column_def.arrLength; i++)
|
||||||
|
{
|
||||||
|
// int Value = std::stoi(rowColumn.Values[i]);
|
||||||
|
// query.addBindValue(QString::fromStdString(rowColumn.Values[i]).toInt());
|
||||||
|
columnData[colIndex++].append(QString::fromStdString(rowColumn.Value).toInt());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// int Value = std::stoi(rowColumn.Value);
|
||||||
|
// query.addBindValue(QString::fromStdString(rowColumn.Value).toInt());
|
||||||
|
columnData[colIndex++].append(QString::fromStdString(rowColumn.Value).toInt());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (column_def.Type == "float")
|
||||||
|
{
|
||||||
|
if (column_def.arrLength > 1)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < column_def.arrLength; i++)
|
||||||
|
{
|
||||||
|
// float Value = std::stof(rowColumn.Values[i]);
|
||||||
|
// query.addBindValue(QString::fromStdString(rowColumn.Values[i]).toFloat());
|
||||||
|
columnData[colIndex++].append(QString::fromStdString(rowColumn.Values[i]).toFloat());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// float Value = std::stof(rowColumn.Value);
|
||||||
|
// query.addBindValue(QString::fromStdString(rowColumn.Value).toFloat());
|
||||||
|
columnData[colIndex++].append(QString::fromStdString(rowColumn.Value).toFloat());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (column_def.Type == "string")
|
||||||
|
{
|
||||||
|
if (column_def.arrLength > 1)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < column_def.arrLength; i++)
|
||||||
|
{
|
||||||
|
// std::string value = rowColumn.Values[i];
|
||||||
|
// query.addBindValue(QString::fromStdString(rowColumn.Values[i]));
|
||||||
|
columnData[colIndex++].append(QString::fromStdString(rowColumn.Values[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// std::string Value = rowColumn.Value;
|
||||||
|
// query.addBindValue(QString::fromStdString(rowColumn.Value));
|
||||||
|
columnData[colIndex++].append(QString::fromStdString(rowColumn.Value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (column_def.Type == "locstring")
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
// query.addBindValue(QString::fromStdString(rowColumn.Values[i]));
|
||||||
|
columnData[colIndex++].append(QString::fromStdString(rowColumn.Values[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& flagValue = record.Columns.at(column_def.Name + "_flags");
|
||||||
|
// query.addBindValue(QString::fromStdString(flagValue.Value).toInt());
|
||||||
|
columnData[colIndex++].append(QString::fromStdString(flagValue.Value).toInt());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (!query.exec())
|
||||||
|
// {
|
||||||
|
// qWarning() << "Insert failed:" << query.lastError().text();
|
||||||
|
// noggit_db.rollback();
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind all columnData at once
|
||||||
|
for (auto& col : columnData)
|
||||||
|
query.addBindValue(col);
|
||||||
|
|
||||||
|
noggit_db.transaction();
|
||||||
|
|
||||||
|
if (!query.execBatch(QSqlQuery::ValuesAsColumns))
|
||||||
|
{
|
||||||
|
qWarning() << "Batch insert failed:" << query.lastError().text();
|
||||||
|
noggit_db.rollback();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
noggit_db.commit();
|
||||||
|
|
||||||
|
qint64 elapsedMs = timer.elapsed();
|
||||||
|
|
||||||
|
qDebug() << "Inserted" << table.RecordCount() << "rows in"
|
||||||
|
<< elapsedMs << "ms ("
|
||||||
|
<< (table.RecordCount() * 1000.0 / elapsedMs) << " rows/sec)";
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get from local dbc data memory stream in BlizzardDatabaseLib::BlizzardDatabase
|
||||||
|
Structures::BlizzardDatabaseRow ClientDatabase::clientRowById(const std::string& tableName, unsigned int id)
|
||||||
|
{
|
||||||
|
auto& table = Noggit::Project::CurrentProject::get()->ClientDatabase->LoadTable(tableName, readFileAsIMemStream);
|
||||||
|
auto record = table.RecordById(id);
|
||||||
|
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get from SQL request to noggit db
|
||||||
|
// never use this function for more than 1 rows, implement a new bulk function
|
||||||
|
Structures::BlizzardDatabaseRow ClientDatabase::sqlRowById(const std::string& tableName, unsigned int id)
|
||||||
|
{
|
||||||
|
auto& db_mgr = Noggit::Sql::DatabaseManager::instance();
|
||||||
|
// Test connection ?
|
||||||
|
|
||||||
|
auto noggit_db = db_mgr.noggitDatabase();
|
||||||
|
|
||||||
|
auto row_definition = Noggit::Project::CurrentProject::get()->ClientDatabase->TableRecordDefinition(tableName);
|
||||||
|
|
||||||
|
QString sql_table_name = getSqlTableName(tableName).c_str();
|
||||||
|
QSqlQuery query(noggit_db);
|
||||||
|
QString sql = QString("SELECT * FROM %1 WHERE ID = :id").arg(sql_table_name);
|
||||||
|
|
||||||
|
query.prepare(sql);
|
||||||
|
query.bindValue(":id", id);
|
||||||
|
|
||||||
|
if (!query.exec())
|
||||||
|
{
|
||||||
|
qWarning() << "Query exec failed:" << query.lastError().text();
|
||||||
|
return BlizzardDatabaseLib::Structures::BlizzardDatabaseRow();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query.next())
|
||||||
|
{
|
||||||
|
QSqlRecord record = query.record();
|
||||||
|
|
||||||
|
auto database_row = Structures::BlizzardDatabaseRow(id);
|
||||||
|
|
||||||
|
// test db def/////////////////////////
|
||||||
|
{
|
||||||
|
auto record_db_def = recordFormat(tableName);
|
||||||
|
if (record.count() != record_db_def.size())
|
||||||
|
{
|
||||||
|
// error : definition deosn't match db structure
|
||||||
|
assert(false);
|
||||||
|
return Structures::BlizzardDatabaseRow(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests construct row from query
|
||||||
|
// TODOOOOOOOOOOOOOOO
|
||||||
|
|
||||||
|
for (int i = 0; i < record_db_def.size(); ++i)
|
||||||
|
{
|
||||||
|
auto& column_db_def = record_db_def[i];
|
||||||
|
QSqlField db_field = record.field(i);
|
||||||
|
|
||||||
|
assert(column_db_def.Name == record.fieldName(i).toStdString());
|
||||||
|
// assert(column_db_def.Type == db_field.type());
|
||||||
|
}
|
||||||
|
}/////////////////////////////////////////
|
||||||
|
|
||||||
|
int field_idx = 0;
|
||||||
|
for (int column_def_idx = 0; column_def_idx < row_definition.ColumnDefinitions.size(); ++column_def_idx)
|
||||||
|
{
|
||||||
|
auto& column_def = row_definition.ColumnDefinitions[column_def_idx];
|
||||||
|
auto database_column = Structures::BlizzardDatabaseColumn();
|
||||||
|
|
||||||
|
auto value = std::string();
|
||||||
|
if (column_def.Type == "locstring")
|
||||||
|
{
|
||||||
|
std::vector<std::string> localizedValues = std::vector<std::string>();
|
||||||
|
for (int loc_idx = 0; loc_idx < 16; loc_idx++)
|
||||||
|
{
|
||||||
|
localizedValues.push_back(query.value(field_idx++).toString().toStdString());
|
||||||
|
}
|
||||||
|
|
||||||
|
database_column.Values = localizedValues;
|
||||||
|
database_row.Columns[column_def.Name] = database_column;
|
||||||
|
|
||||||
|
// currently loc mask is set to a separate column because wdbc reader does it.
|
||||||
|
auto loc_mask_column = Structures::BlizzardDatabaseColumn();
|
||||||
|
loc_mask_column.Value = query.value(field_idx++).toString().toStdString();
|
||||||
|
database_row.Columns[column_def.Name + "_flags"] = loc_mask_column;
|
||||||
|
}
|
||||||
|
else // every other type than locstring
|
||||||
|
{
|
||||||
|
if (column_def.arrLength > 1) // array
|
||||||
|
{
|
||||||
|
for (int i = 0; i < column_def.arrLength; i++)
|
||||||
|
{
|
||||||
|
auto Value = query.value(field_idx++);
|
||||||
|
database_column.Values.push_back(Value.toString().toStdString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // single value
|
||||||
|
{
|
||||||
|
auto Value = query.value(field_idx++);
|
||||||
|
value = Value.toString().toStdString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
database_column.Value = value;
|
||||||
|
database_row.Columns[column_def.Name] = database_column;
|
||||||
|
}
|
||||||
|
|
||||||
|
return database_row;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qWarning() << "No row found in" << tableName.c_str() << "for ID =" << id;
|
||||||
|
return BlizzardDatabaseLib::Structures::BlizzardDatabaseRow();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClientDatabase::createSQLTableIfNotExist(const BlizzardDatabaseLib::BlizzardDatabaseTable& table)
|
||||||
|
{
|
||||||
|
const std::string table_name = table.Name();
|
||||||
|
auto row_definition = table.GetRecordDefinition();
|
||||||
|
|
||||||
|
const std::string sql_table_name = getSqlTableName(table_name);
|
||||||
|
std::string statement = std::format("CREATE TABLE IF NOT EXISTS `{}` (", sql_table_name);
|
||||||
|
|
||||||
|
std::string primary_key_name;
|
||||||
|
|
||||||
|
auto db_record_format = recordFormat(table_name);
|
||||||
|
|
||||||
|
assert(db_record_format.size() == table.ColumnCount());
|
||||||
|
|
||||||
|
for (auto& db_column_format : db_record_format)
|
||||||
|
{
|
||||||
|
statement += std::format("`{}` {}", db_column_format.Name, db_column_format.Type);
|
||||||
|
|
||||||
|
if (db_column_format.Type == "TEXT")
|
||||||
|
{
|
||||||
|
statement += " NULL"; // allow NULL by default
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!db_column_format.isSigned && db_column_format.Type == "INT")
|
||||||
|
{
|
||||||
|
// assert(db_column_format.Type == "INT");
|
||||||
|
statement += " UNSIGNED"; // only allow int to be unsigned?
|
||||||
|
}
|
||||||
|
statement += " NOT NULL"; // allow text to be nulled
|
||||||
|
statement += " DEFAULT 0";
|
||||||
|
}
|
||||||
|
|
||||||
|
statement += ",\n";
|
||||||
|
|
||||||
|
if (db_column_format.isID)
|
||||||
|
{
|
||||||
|
assert(primary_key_name.empty()); // more than one key ? TODO
|
||||||
|
primary_key_name = db_column_format.Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!primary_key_name.empty())
|
||||||
|
statement += std::format("PRIMARY KEY (`{}`)", primary_key_name);
|
||||||
|
|
||||||
|
// Add indexes for relations
|
||||||
|
for (auto& db_column_format : db_record_format)
|
||||||
|
{
|
||||||
|
if (db_column_format.isRelation && !db_column_format.isID) {
|
||||||
|
statement += std::format(",\nINDEX (`{}`)", db_column_format.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// statement += ")\n ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 DEFAULT COLLATE='utf8mb4_general_ci';";
|
||||||
|
statement += ")\n ENGINE = InnoDB;";
|
||||||
|
|
||||||
|
auto& db_mgr = Noggit::Sql::DatabaseManager::instance();
|
||||||
|
bool valid_conn = db_mgr.testConnection(Noggit::Sql::SQLDbType::Noggit);
|
||||||
|
if (!valid_conn)
|
||||||
|
return false;
|
||||||
|
auto noggit_db = db_mgr.noggitDatabase();
|
||||||
|
|
||||||
|
QSqlQuery query(noggit_db);
|
||||||
|
bool success = query.exec(QString::fromStdString(statement));
|
||||||
|
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
qDebug() << "Failed to create table:" << query.lastError().text();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qDebug() << "Table " << table_name.c_str() << " created or already exists.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ClientDatabase::getSqlTableName(const std::string& db_name, unsigned int build_id)
|
||||||
|
{
|
||||||
|
if (build_id == 0)
|
||||||
|
build_id = Noggit::Project::CurrentProject::get()->buildId();
|
||||||
|
|
||||||
|
std::string table = std::format("db_{}_{}", db_name, build_id);
|
||||||
|
|
||||||
|
// convert to lowercase for compatibility with SQL
|
||||||
|
std::transform(table.begin(), table.end(), table.begin(),
|
||||||
|
[](unsigned char c) { return std::tolower(c); });
|
||||||
|
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<DbColumnFormat> ClientDatabase::recordFormat(const std::string& table_name)
|
||||||
|
{
|
||||||
|
auto record_format = std::vector<DbColumnFormat>();
|
||||||
|
|
||||||
|
auto row_definition = Noggit::Project::CurrentProject::get()->ClientDatabase->TableRecordDefinition(table_name);
|
||||||
|
|
||||||
|
for (int col_idx = 0; col_idx < row_definition.ColumnDefinitions.size(); col_idx++)
|
||||||
|
{
|
||||||
|
auto& column_def = row_definition.ColumnDefinitions[col_idx];
|
||||||
|
|
||||||
|
bool is_locstring = false;
|
||||||
|
|
||||||
|
// convert dbd definition type names to real format
|
||||||
|
// TODO : map types
|
||||||
|
std::string sql_data_type = "INT";
|
||||||
|
if (BlizzardDatabaseLib::Extension::String::Compare(column_def.Type, "int"))
|
||||||
|
{
|
||||||
|
sql_data_type = "INT";
|
||||||
|
}
|
||||||
|
else if (BlizzardDatabaseLib::Extension::String::Compare(column_def.Type, "float"))
|
||||||
|
{
|
||||||
|
sql_data_type = "FLOAT";
|
||||||
|
}
|
||||||
|
else if (BlizzardDatabaseLib::Extension::String::Compare(column_def.Type, "string"))
|
||||||
|
{
|
||||||
|
sql_data_type = "TEXT";
|
||||||
|
}
|
||||||
|
else if (BlizzardDatabaseLib::Extension::String::Compare(column_def.Type, "locstring"))
|
||||||
|
{
|
||||||
|
sql_data_type = "TEXT";
|
||||||
|
is_locstring = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
assert(false);
|
||||||
|
|
||||||
|
int array_size = 1;
|
||||||
|
if (column_def.arrLength > 1)
|
||||||
|
{
|
||||||
|
array_size = column_def.arrLength;
|
||||||
|
}
|
||||||
|
if (is_locstring)
|
||||||
|
array_size = 16;
|
||||||
|
|
||||||
|
for (int i = 0; i < array_size; i++)
|
||||||
|
{
|
||||||
|
DbColumnFormat db_col_format;
|
||||||
|
std::string col_name = "";
|
||||||
|
|
||||||
|
if (array_size == 1)
|
||||||
|
{
|
||||||
|
col_name = column_def.Name;
|
||||||
|
}
|
||||||
|
else if (is_locstring)
|
||||||
|
{
|
||||||
|
col_name = std::format("{}_{}", column_def.Name, dbc_string_loc_names[i]); // {MapName_lang}_{enUS}
|
||||||
|
}
|
||||||
|
else if (array_size > 1)
|
||||||
|
{
|
||||||
|
col_name = std::format("{}_{}", column_def.Name, i); // {MapName}_{0}
|
||||||
|
}
|
||||||
|
db_col_format.Name = col_name;
|
||||||
|
db_col_format.Type = sql_data_type;
|
||||||
|
|
||||||
|
assert(!(column_def.isID && array_size > 1));
|
||||||
|
db_col_format.isID = column_def.isID;
|
||||||
|
db_col_format.isRelation = column_def.isRelation;
|
||||||
|
db_col_format.isSigned = column_def.isSigned;
|
||||||
|
|
||||||
|
record_format.push_back(db_col_format);
|
||||||
|
}
|
||||||
|
if (is_locstring) // add lang mask column
|
||||||
|
{
|
||||||
|
DbColumnFormat db_col_format;
|
||||||
|
db_col_format.Name = std::format("{}_flags", column_def.Name);
|
||||||
|
db_col_format.Type = "INT";
|
||||||
|
db_col_format.isSigned = false;
|
||||||
|
db_col_format.isID = false;
|
||||||
|
db_col_format.isRelation = false;
|
||||||
|
record_format.push_back(db_col_format);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return record_format;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
65
src/noggit/sql/ClientDatabase.h
Normal file
65
src/noggit/sql/ClientDatabase.h
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <blizzard-database-library/include/BlizzardDatabase.h>
|
||||||
|
#include <blizzard-database-library/include/structures/FileStructures.h>
|
||||||
|
|
||||||
|
#include <noggit/sql/DatabaseManager.h>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
|
||||||
|
constexpr const char* dbc_string_loc_names[16] = { "enUS", "koKR", "frFR", "deDE", "zhCN",
|
||||||
|
"zhTW", "esES", "esMX", "ruRU", "jaJP", "ptPT", "itIT",
|
||||||
|
"unk_12", "unk_13", "unk_14", "unk_15" };
|
||||||
|
|
||||||
|
using namespace BlizzardDatabaseLib;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace Noggit
|
||||||
|
{
|
||||||
|
struct DbColumnFormat
|
||||||
|
{
|
||||||
|
std::string Type = "";
|
||||||
|
std::string Name = "";
|
||||||
|
// int size;
|
||||||
|
bool isID = false;
|
||||||
|
bool isRelation = false;
|
||||||
|
bool isSigned = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// calls client or server db adaptively. so /sql/ is not really a good location
|
||||||
|
class ClientDatabase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// static ClientDatabase& instance()
|
||||||
|
// {
|
||||||
|
// static ClientDatabase _instance;
|
||||||
|
// return _instance;
|
||||||
|
// }
|
||||||
|
|
||||||
|
static std::optional<Structures::BlizzardDatabaseRow> getRowById(const std::string& tableName, unsigned int id); // constructs a row either from db or client
|
||||||
|
|
||||||
|
static bool testUploadDBCtoDB(BlizzardDatabaseLib::BlizzardDatabaseTable& table);
|
||||||
|
|
||||||
|
static void TODODeploySqlToClient();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// ClientDatabase() = default;
|
||||||
|
// ~ClientDatabase() = default;
|
||||||
|
// ClientDatabase(const ClientDatabase&) = delete;
|
||||||
|
// ClientDatabase& operator=(const ClientDatabase&) = delete;
|
||||||
|
|
||||||
|
|
||||||
|
static Structures::BlizzardDatabaseRow clientRowById(const std::string& tableName, unsigned int id);
|
||||||
|
static Structures::BlizzardDatabaseRow sqlRowById(const std::string& tableName, unsigned int id);
|
||||||
|
|
||||||
|
static bool createSQLTableIfNotExist(const BlizzardDatabaseLib::BlizzardDatabaseTable& table);
|
||||||
|
|
||||||
|
static std::string getSqlTableName(const std::string& db_name, unsigned int build_id = 0); // get automatically from project if default(0)
|
||||||
|
|
||||||
|
static std::vector<DbColumnFormat> recordFormat(const std::string& table_name); // true record format for all columns, not array size/loc etc. eg returns all 17 columns for loc.
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
0
src/noggit/sql/DatabaseManager.cpp
Normal file
0
src/noggit/sql/DatabaseManager.cpp
Normal file
236
src/noggit/sql/DatabaseManager.h
Normal file
236
src/noggit/sql/DatabaseManager.h
Normal file
@@ -0,0 +1,236 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <QSqlDatabase>
|
||||||
|
#include <QString>
|
||||||
|
#include <QSqlError>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QSqlQuery>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
// Connections are currently not thread safe ! would need temporary connection copies per thread.
|
||||||
|
namespace Noggit::Sql
|
||||||
|
{
|
||||||
|
enum class SQLDbType
|
||||||
|
{
|
||||||
|
Noggit,
|
||||||
|
World
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SqlDriver
|
||||||
|
{
|
||||||
|
MySQL,
|
||||||
|
// SQLite,
|
||||||
|
// PostgreSQL
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DbConfig
|
||||||
|
{
|
||||||
|
QString host;
|
||||||
|
int port = 3306;
|
||||||
|
QString dbName;
|
||||||
|
QString user;
|
||||||
|
QString password;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DatabaseManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static DatabaseManager& instance()
|
||||||
|
{
|
||||||
|
static DatabaseManager _instance;
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool initializeDb(SQLDbType type,
|
||||||
|
const QString& host, int port,
|
||||||
|
const QString& dbName, const QString& user, const QString& password)
|
||||||
|
{
|
||||||
|
DbConfig newConfig{ host, port, dbName, user, password };
|
||||||
|
|
||||||
|
// If config is unchanged and connection is alive, nothing to do
|
||||||
|
if (configs[type].host == host &&
|
||||||
|
configs[type].port == port &&
|
||||||
|
configs[type].dbName == dbName &&
|
||||||
|
configs[type].user == user &&
|
||||||
|
configs[type].password == password &&
|
||||||
|
testConnection(type))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
configs[type] = newConfig;
|
||||||
|
|
||||||
|
QString connName = connectionName(type);
|
||||||
|
|
||||||
|
// remove old connection if it exists
|
||||||
|
if (QSqlDatabase::contains(connName))
|
||||||
|
{
|
||||||
|
QSqlDatabase oldDb = QSqlDatabase::database(connName);
|
||||||
|
if (oldDb.isOpen())
|
||||||
|
oldDb.close();
|
||||||
|
QSqlDatabase::removeDatabase(connName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new connection
|
||||||
|
QSqlDatabase db = QSqlDatabase::addDatabase(driverToString(SqlDriver::MySQL), connName);
|
||||||
|
db.setHostName(host);
|
||||||
|
db.setPort(port);
|
||||||
|
// db.setDatabaseName(dbName);
|
||||||
|
db.setUserName(user);
|
||||||
|
db.setPassword(password);
|
||||||
|
|
||||||
|
// connect to my sql without a database
|
||||||
|
if (!db.open())
|
||||||
|
{
|
||||||
|
qWarning() << "Failed to connect to database " << dbName << "on host" << host << ":" << db.lastError().text();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create database if it doesn't exist
|
||||||
|
QSqlQuery query(db);
|
||||||
|
if (!query.exec(QStringLiteral("CREATE DATABASE IF NOT EXISTS `%1`").arg(dbName)))
|
||||||
|
{
|
||||||
|
qWarning() << "Failed to open database " << dbName << ":" << db.lastError().text();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// now attempt to connect to db
|
||||||
|
// Need to close connection first because it needs to create the connection with a databasename.
|
||||||
|
db.close();
|
||||||
|
db.setDatabaseName(dbName);
|
||||||
|
if (!db.open())
|
||||||
|
{
|
||||||
|
qDebug() << "Failed to open database:" << db.lastError().text();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
qDebug() << db.tables();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// requires database to be initialized
|
||||||
|
bool testConnection(SQLDbType type) const
|
||||||
|
{
|
||||||
|
if (!configs.contains(type))
|
||||||
|
{
|
||||||
|
qWarning() << "No configuration for database type" << static_cast<int>(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
QSqlDatabase db = database(type);
|
||||||
|
if (db.isValid() && db.isOpen())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// If the connection is invalid or closed, attempt to open it
|
||||||
|
if (!db.open())
|
||||||
|
{
|
||||||
|
qWarning() << "Connection test failed for" << db.connectionName() << ":" << db.lastError().text();
|
||||||
|
qDebug() << db.lastError().nativeErrorCode();
|
||||||
|
qDebug() << db.lastError().databaseText();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qDebug() << "Reconnected to database" << db.connectionName();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool testConnectionWithPopup(SQLDbType type, bool report_only_error) const
|
||||||
|
{
|
||||||
|
QMessageBox prompt;
|
||||||
|
prompt.setWindowFlag(Qt::WindowStaysOnTopHint);
|
||||||
|
bool success = false;
|
||||||
|
std::stringstream promptText;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
success = testConnection(type);
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
success = false;
|
||||||
|
|
||||||
|
promptText << "\n# ERR: " << e.what();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (success && !report_only_error)
|
||||||
|
{
|
||||||
|
prompt.setIcon(QMessageBox::Information);
|
||||||
|
prompt.setText("Succesfully connected to MySQL database.");
|
||||||
|
prompt.setWindowTitle("Success");
|
||||||
|
|
||||||
|
if (!report_only_error)
|
||||||
|
prompt.exec();
|
||||||
|
}
|
||||||
|
else if (!success)
|
||||||
|
{
|
||||||
|
prompt.setIcon(QMessageBox::Warning);
|
||||||
|
prompt.setText("Failed to load MySQL database, check your settings. \nIf you did not intend to use this feature, disable it in Noggit->settings->MySQL");
|
||||||
|
prompt.setWindowTitle("Noggit Database Error");
|
||||||
|
// disable if connection is not valid
|
||||||
|
// settings.value("project/mysql/enabled") = false;
|
||||||
|
|
||||||
|
promptText << database(type).lastError().text().toStdString() << std::endl;
|
||||||
|
promptText << database(type).lastError().nativeErrorCode().toStdString() << std::endl;
|
||||||
|
promptText << database(type).lastError().databaseText().toStdString() << std::endl;
|
||||||
|
|
||||||
|
prompt.setInformativeText(promptText.str().c_str());
|
||||||
|
prompt.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isDriverAvailable()
|
||||||
|
{
|
||||||
|
QStringList availableDrivers = QSqlDatabase::drivers();
|
||||||
|
return availableDrivers.contains(driverToString(_sql_driver), Qt::CaseInsensitive);
|
||||||
|
}
|
||||||
|
|
||||||
|
QSqlDatabase database(SQLDbType type) const
|
||||||
|
{
|
||||||
|
return QSqlDatabase::database(connectionName(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
QSqlDatabase noggitDatabase() const
|
||||||
|
{
|
||||||
|
return DatabaseManager::database(SQLDbType::Noggit);
|
||||||
|
}
|
||||||
|
|
||||||
|
QSqlDatabase worldDatabase() const
|
||||||
|
{
|
||||||
|
return DatabaseManager::database(SQLDbType::World);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
DatabaseManager() = default;
|
||||||
|
~DatabaseManager() = default;
|
||||||
|
DatabaseManager(const DatabaseManager&) = delete;
|
||||||
|
DatabaseManager& operator=(const DatabaseManager&) = delete;
|
||||||
|
|
||||||
|
SqlDriver _sql_driver = SqlDriver::MySQL;
|
||||||
|
|
||||||
|
mutable QMap<SQLDbType, DbConfig> configs; // stores current configuration per DB type
|
||||||
|
|
||||||
|
QString connectionName(SQLDbType type) const
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case SQLDbType::Noggit: return "noggit";
|
||||||
|
case SQLDbType::World: return "world";
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QString driverToString(SqlDriver driver)
|
||||||
|
{
|
||||||
|
switch (driver)
|
||||||
|
{
|
||||||
|
case SqlDriver::MySQL: return "QMYSQL";
|
||||||
|
// case SqlDriver::SQLite: return "QSQLITE";
|
||||||
|
// case SqlDriver::PostgreSQL: return "QPSQL";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
107
src/noggit/sql/SqlUIDStorage.cpp
Normal file
107
src/noggit/sql/SqlUIDStorage.cpp
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
#include "SqlUIDStorage.h"
|
||||||
|
|
||||||
|
bool Noggit::Sql::SqlUIDStorage::hasMaxUIDStoredDB(std::size_t mapID)
|
||||||
|
{
|
||||||
|
auto& db_mgr = DatabaseManager::instance();
|
||||||
|
|
||||||
|
bool valid_conn = db_mgr.testConnection(SQLDbType::Noggit);
|
||||||
|
if (!valid_conn)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto noggit_db = db_mgr.noggitDatabase();
|
||||||
|
|
||||||
|
QSqlQuery query(noggit_db);
|
||||||
|
query.prepare(QStringLiteral("SELECT * FROM `UIDs` WHERE `_map_id` = ?"));
|
||||||
|
query.addBindValue(static_cast<int>(mapID));
|
||||||
|
|
||||||
|
if (!query.exec())
|
||||||
|
{
|
||||||
|
qWarning() << "Failed to check UIDs:" << query.lastError().text();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return query.next(); // true if at least one row exists
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint32_t Noggit::Sql::SqlUIDStorage::getGUIDFromDB(std::size_t mapID)
|
||||||
|
{
|
||||||
|
auto& db_mgr = Sql::DatabaseManager::instance();
|
||||||
|
|
||||||
|
bool valid_conn = db_mgr.testConnection(SQLDbType::Noggit);
|
||||||
|
if (!valid_conn)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
QSqlDatabase noggit_db = db_mgr.noggitDatabase();
|
||||||
|
/////
|
||||||
|
QSqlQuery query(noggit_db);
|
||||||
|
query.prepare(QStringLiteral("SELECT `UID` FROM `UIDs` WHERE `_map_id` = ?"));
|
||||||
|
query.addBindValue(static_cast<int>(mapID));
|
||||||
|
|
||||||
|
if (!query.exec())
|
||||||
|
{
|
||||||
|
qWarning() << "Failed to fetch UID from db:" << query.lastError().text();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query.next())
|
||||||
|
return query.value(0).toUInt();
|
||||||
|
|
||||||
|
return 0; // no rows
|
||||||
|
|
||||||
|
// Optional, find highest GUID of all maps.
|
||||||
|
// "SELECT `UID` FROM `UIDs`"
|
||||||
|
// std::uint32_t highGUID(0);
|
||||||
|
// if (res->rowsCount() == 0)
|
||||||
|
// {
|
||||||
|
// return 0;
|
||||||
|
// }
|
||||||
|
// while (res->next())
|
||||||
|
// {
|
||||||
|
// highGUID = res->getInt(1);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// return highGUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Noggit::Sql::SqlUIDStorage::insertUIDinDB(std::size_t mapID, std::uint32_t NewUID)
|
||||||
|
{
|
||||||
|
auto& db_mgr = Sql::DatabaseManager::instance();
|
||||||
|
bool valid_conn = db_mgr.testConnection(SQLDbType::Noggit);
|
||||||
|
if (!valid_conn)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSqlDatabase noggit_db = db_mgr.noggitDatabase();
|
||||||
|
|
||||||
|
QSqlQuery query(noggit_db);
|
||||||
|
query.prepare(QStringLiteral("INSERT INTO `UIDs` (`_map_id`, `UID`) VALUES (?, ?)"));
|
||||||
|
query.addBindValue(static_cast<int>(mapID));
|
||||||
|
query.addBindValue(static_cast<int>(NewUID));
|
||||||
|
|
||||||
|
if (!query.exec())
|
||||||
|
{
|
||||||
|
qWarning() << "Failed to insert UID in db: " << query.lastError().text();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Noggit::Sql::SqlUIDStorage::updateUIDinDB(std::size_t mapID, std::uint32_t NewUID)
|
||||||
|
{
|
||||||
|
auto& db_mgr = Sql::DatabaseManager::instance();
|
||||||
|
|
||||||
|
if (!db_mgr.testConnection(SQLDbType::Noggit))
|
||||||
|
return;
|
||||||
|
|
||||||
|
QSqlDatabase noggit_db = db_mgr.noggitDatabase();
|
||||||
|
|
||||||
|
QSqlQuery query(noggit_db);
|
||||||
|
query.prepare(QStringLiteral("UPDATE `UIDs` SET `UID` = ? WHERE `_map_id` = ?"));
|
||||||
|
query.addBindValue(static_cast<int>(NewUID));
|
||||||
|
query.addBindValue(static_cast<int>(mapID));
|
||||||
|
|
||||||
|
if (!query.exec())
|
||||||
|
{
|
||||||
|
qWarning() << "Failed to update UID:" << query.lastError().text();
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/noggit/sql/SqlUIDStorage.h
Normal file
16
src/noggit/sql/SqlUIDStorage.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <noggit/sql/DatabaseManager.h>
|
||||||
|
|
||||||
|
namespace Noggit::Sql
|
||||||
|
{
|
||||||
|
class SqlUIDStorage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static bool hasMaxUIDStoredDB(std::size_t mapID);
|
||||||
|
static std::uint32_t getGUIDFromDB(std::size_t mapID);
|
||||||
|
static void insertUIDinDB(std::size_t mapID, std::uint32_t NewUID);
|
||||||
|
static void updateUIDinDB(std::size_t mapID, std::uint32_t NewUID);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@@ -14,6 +14,7 @@
|
|||||||
#include <noggit/World.h>
|
#include <noggit/World.h>
|
||||||
|
|
||||||
#include <blizzard-database-library/include/BlizzardDatabase.h>
|
#include <blizzard-database-library/include/BlizzardDatabase.h>
|
||||||
|
#include <noggit/sql/ClientDatabase.h>
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QButtonGroup>
|
#include <QButtonGroup>
|
||||||
@@ -33,6 +34,7 @@
|
|||||||
#include <QSpinBox>
|
#include <QSpinBox>
|
||||||
#include <QStackedWidget>
|
#include <QStackedWidget>
|
||||||
#include <QWheelEvent>
|
#include <QWheelEvent>
|
||||||
|
#include <QtCore/QSettings>
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
@@ -629,7 +631,22 @@ void MapCreationWizard::selectMap(int map_id)
|
|||||||
// int map_id = world->getMapID();
|
// int map_id = world->getMapID();
|
||||||
|
|
||||||
auto table = _project->ClientDatabase->LoadTable("Map", readFileAsIMemStream);
|
auto table = _project->ClientDatabase->LoadTable("Map", readFileAsIMemStream);
|
||||||
auto record = table.Record(map_id);
|
auto record = table.RecordById(map_id);
|
||||||
|
|
||||||
|
|
||||||
|
/// test area, delete later
|
||||||
|
// auto table = _project->ClientDatabase->GetTable("Map");
|
||||||
|
QSettings settings;
|
||||||
|
|
||||||
|
bool use_mysql = settings.value("project/mysql/enabled", false).toBool();
|
||||||
|
if (use_mysql)
|
||||||
|
{
|
||||||
|
// bool valid_conn = mysql::testConnection(true);
|
||||||
|
Noggit::ClientDatabase::testUploadDBCtoDB(table);
|
||||||
|
|
||||||
|
}
|
||||||
|
///////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
_cur_map_id = map_id;
|
_cur_map_id = map_id;
|
||||||
|
|
||||||
@@ -762,7 +779,7 @@ void MapCreationWizard::selectMapDifficulty()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
auto difficulty_table = _project->ClientDatabase->LoadTable("MapDifficulty", readFileAsIMemStream);
|
auto difficulty_table = _project->ClientDatabase->LoadTable("MapDifficulty", readFileAsIMemStream);
|
||||||
auto record = difficulty_table.Record(selected_difficulty_id);
|
auto record = difficulty_table.RecordById(selected_difficulty_id);
|
||||||
|
|
||||||
//_difficulty_type;
|
//_difficulty_type;
|
||||||
_difficulty_req_message->fill(record, "Message_lang");
|
_difficulty_req_message->fill(record, "Message_lang");
|
||||||
|
|||||||
@@ -21,6 +21,8 @@
|
|||||||
#include <noggit/ui/windows/settingsPanel/SettingsPanel.h>
|
#include <noggit/ui/windows/settingsPanel/SettingsPanel.h>
|
||||||
#include <noggit/uid_storage.hpp>
|
#include <noggit/uid_storage.hpp>
|
||||||
#include <noggit/World.h>
|
#include <noggit/World.h>
|
||||||
|
#include <noggit/sql/SqlUIDStorage.h>
|
||||||
|
#include <noggit/sql/ClientDatabase.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <blizzard-archive-library/include/Exception.hpp>
|
#include <blizzard-archive-library/include/Exception.hpp>
|
||||||
@@ -43,16 +45,11 @@
|
|||||||
#include <QtWidgets/QTabWidget>
|
#include <QtWidgets/QTabWidget>
|
||||||
#include <QtWidgets/QVBoxLayout>
|
#include <QtWidgets/QVBoxLayout>
|
||||||
#include <QtWidgets/QWidget>
|
#include <QtWidgets/QWidget>
|
||||||
|
#include <QtCore/QSettings>
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#ifdef USE_MYSQL_UID_STORAGE
|
|
||||||
#include <mysql/mysql.h>
|
|
||||||
|
|
||||||
#include <QtCore/QSettings>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "revision.h"
|
#include "revision.h"
|
||||||
|
|
||||||
#include "ui_TitleBar.h"
|
#include "ui_TitleBar.h"
|
||||||
@@ -84,18 +81,32 @@ namespace Noggit::Ui::Windows
|
|||||||
LogError << "NoggitWindow() : Unsupported project version, skipping loading DBCs." << std::endl;
|
LogError << "NoggitWindow() : Unsupported project version, skipping loading DBCs." << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_settings = new settings(this);
|
||||||
|
|
||||||
|
QSettings settings;
|
||||||
|
// connect to databases
|
||||||
|
bool use_mysql = settings.value("project/mysql/enabled", false).toBool();
|
||||||
|
if (use_mysql)
|
||||||
|
{
|
||||||
|
auto host = settings.value("project/mysql/server").toString();
|
||||||
|
auto port = settings.value("project/mysql/port", "3306").toInt();
|
||||||
|
auto db_name = settings.value("project/mysql/db").toString(); // schema name
|
||||||
|
auto user = settings.value("project/mysql/user").toString();
|
||||||
|
auto pass = settings.value("project/mysql/pwd").toString();
|
||||||
|
|
||||||
|
auto& db_manager = Sql::DatabaseManager::instance();
|
||||||
|
db_manager.initializeDb(Sql::SQLDbType::Noggit, host, port, db_name, user, pass);
|
||||||
|
}
|
||||||
|
|
||||||
setCentralWidget(_null_widget);
|
setCentralWidget(_null_widget);
|
||||||
|
|
||||||
// The default value is AnimatedDocks | AllowTabbedDocks.
|
// The default value is AnimatedDocks | AllowTabbedDocks.
|
||||||
setDockOptions(AnimatedDocks | AllowNestedDocks | AllowTabbedDocks | GroupedDragging);
|
setDockOptions(AnimatedDocks | AllowNestedDocks | AllowTabbedDocks | GroupedDragging);
|
||||||
|
|
||||||
_about = new about(this);
|
_about = new about(this);
|
||||||
_settings = new settings(this);
|
|
||||||
|
|
||||||
_menuBar = menuBar();
|
_menuBar = menuBar();
|
||||||
|
|
||||||
QSettings settings;
|
|
||||||
|
|
||||||
if (!settings.value("systemWindowFrame", true).toBool())
|
if (!settings.value("systemWindowFrame", true).toBool())
|
||||||
{
|
{
|
||||||
QWidget* widget = new QWidget(this);
|
QWidget* widget = new QWidget(this);
|
||||||
@@ -159,16 +170,9 @@ namespace Noggit::Ui::Windows
|
|||||||
|
|
||||||
unsigned int world_map_id = getWorld()->getMapID();
|
unsigned int world_map_id = getWorld()->getMapID();
|
||||||
|
|
||||||
#ifdef USE_MYSQL_UID_STORAGE
|
|
||||||
bool use_mysql = settings.value("project/mysql/enabled", false).toBool();
|
bool use_mysql = settings.value("project/mysql/enabled", false).toBool();
|
||||||
|
|
||||||
bool valid_conn = false;
|
if ((Noggit::Sql::SqlUIDStorage::hasMaxUIDStoredDB(world_map_id))
|
||||||
if (use_mysql)
|
|
||||||
{
|
|
||||||
valid_conn = mysql::testConnection(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((valid_conn && mysql::hasMaxUIDStoredDB(world_map_id))
|
|
||||||
|| uid_storage::hasMaxUIDStored(world_map_id)
|
|| uid_storage::hasMaxUIDStored(world_map_id)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@@ -176,7 +180,8 @@ namespace Noggit::Ui::Windows
|
|||||||
getWorld()->mapIndex.loadMaxUID();
|
getWorld()->mapIndex.loadMaxUID();
|
||||||
enterMapAt(pos, camera_pitch, camera_yaw, uid_fix_mode::none, from_bookmark);
|
enterMapAt(pos, camera_pitch, camera_yaw, uid_fix_mode::none, from_bookmark);
|
||||||
}
|
}
|
||||||
#else
|
// old if no mysql block
|
||||||
|
/*
|
||||||
if (uid_storage::hasMaxUIDStored(world_map_id))
|
if (uid_storage::hasMaxUIDStored(world_map_id))
|
||||||
{
|
{
|
||||||
if (settings.value("uid_startup_check", true).toBool())
|
if (settings.value("uid_startup_check", true).toBool())
|
||||||
@@ -187,8 +192,7 @@ namespace Noggit::Ui::Windows
|
|||||||
getWorld()->mapIndex.loadMaxUID();
|
getWorld()->mapIndex.loadMaxUID();
|
||||||
enterMapAt(pos, camera_pitch, camera_yaw, uid_fix_mode::none, from_bookmark);
|
enterMapAt(pos, camera_pitch, camera_yaw, uid_fix_mode::none, from_bookmark);
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
#endif
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto uid_fix_window(new UidFixWindow(pos, camera_pitch, camera_yaw));
|
auto uid_fix_window(new UidFixWindow(pos, camera_pitch, camera_yaw));
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <noggit/Log.h>
|
#include <noggit/Log.h>
|
||||||
#include <noggit/ui/FramelessWindow.hpp>
|
#include <noggit/ui/FramelessWindow.hpp>
|
||||||
#include <noggit/ui/windows/settingsPanel/SettingsPanel.h>
|
#include <noggit/ui/windows/settingsPanel/SettingsPanel.h>
|
||||||
|
#include <noggit/sql/DatabaseManager.h>
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QtCore/QSettings>
|
#include <QtCore/QSettings>
|
||||||
@@ -10,13 +11,10 @@
|
|||||||
#include <QtWidgets/QFileDialog>
|
#include <QtWidgets/QFileDialog>
|
||||||
#include <QtWidgets/QPushButton>
|
#include <QtWidgets/QPushButton>
|
||||||
|
|
||||||
#ifdef USE_MYSQL_UID_STORAGE
|
|
||||||
#include <mysql/mysql.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <ui_SettingsPanel.h>
|
#include <ui_SettingsPanel.h>
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
|
||||||
namespace Noggit
|
namespace Noggit
|
||||||
@@ -79,11 +77,9 @@ namespace Noggit
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
#ifdef USE_MYSQL_UID_STORAGE
|
|
||||||
ui->MySQL_box->setEnabled(true);
|
ui->MySQL_box->setEnabled(true);
|
||||||
ui->MySQL_box->setCheckable(true);
|
ui->MySQL_box->setCheckable(true);
|
||||||
ui->mysql_warning->setVisible(false);
|
ui->mysql_warning->setVisible(false);
|
||||||
#endif
|
|
||||||
|
|
||||||
ui->_theme->addItem("System");
|
ui->_theme->addItem("System");
|
||||||
|
|
||||||
@@ -170,10 +166,55 @@ namespace Noggit
|
|||||||
|
|
||||||
connect(ui->mysql_connect_test, &QPushButton::clicked, [this]
|
connect(ui->mysql_connect_test, &QPushButton::clicked, [this]
|
||||||
{
|
{
|
||||||
save_changes();
|
// test button for noggit db only !
|
||||||
#ifdef USE_MYSQL_UID_STORAGE
|
|
||||||
mysql::testConnection();
|
// save_changes(); // old method saved and only used qsetting
|
||||||
#endif
|
|
||||||
|
auto& db_manager = Sql::DatabaseManager::instance();
|
||||||
|
|
||||||
|
if (!db_manager.isDriverAvailable())
|
||||||
|
{
|
||||||
|
qDebug() << "Available drivers:" << QSqlDatabase::drivers();
|
||||||
|
|
||||||
|
// SPECIAL MISSING/currupted driver DLL POPUP
|
||||||
|
QMessageBox prompt;
|
||||||
|
prompt.setWindowFlag(Qt::WindowStaysOnTopHint);
|
||||||
|
prompt.setIcon(QMessageBox::Critical);
|
||||||
|
prompt.setText("mySQL driver could not be loaded.");
|
||||||
|
prompt.setWindowTitle("Noggit Database Error");
|
||||||
|
|
||||||
|
std::stringstream promptText;
|
||||||
|
promptText << "Make sure <Noggit/sqldrivers/qsqlmysql.dll> exists.\n";
|
||||||
|
promptText << "If not, it can be downloaded at https://github.com/thecodemonkey86/qt_mysql_driver/releases \n";
|
||||||
|
promptText << "Noggit Qt version :" << QT_VERSION_STR;
|
||||||
|
|
||||||
|
prompt.setInformativeText("Make sure Noggit/sqldrivers/qsqlmysql.dll exists."
|
||||||
|
"If not, it can be downloaded at ");
|
||||||
|
prompt.exec();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString host = ui->_mysql_server_field->text();
|
||||||
|
QString user = ui->_mysql_user_field->text();
|
||||||
|
QString pass = ui->_mysql_pwd_field->text();
|
||||||
|
QString db_name = ui->_mysql_db_field->text();
|
||||||
|
int port = ui->_mysql_port_field->value();
|
||||||
|
|
||||||
|
// test temporary connection from text fields
|
||||||
|
bool test1 = db_manager.initializeDb(Sql::SQLDbType::Noggit, host, port, db_name, user, pass);
|
||||||
|
bool test2 = db_manager.testConnectionWithPopup(Sql::SQLDbType::Noggit, false);
|
||||||
|
|
||||||
|
// reconnect to saved db from settings
|
||||||
|
QSettings settings;
|
||||||
|
host = settings.value("project/mysql/server").toString();
|
||||||
|
port = settings.value("project/mysql/port", "3306").toInt();
|
||||||
|
db_name = settings.value("project/mysql/db").toString(); // schema name
|
||||||
|
user = settings.value("project/mysql/user").toString();
|
||||||
|
pass = settings.value("project/mysql/pwd").toString();
|
||||||
|
|
||||||
|
bool test3 = db_manager.initializeDb(Sql::SQLDbType::Noggit, host, port, db_name, user, pass);
|
||||||
|
assert(db_manager.testConnection(Sql::SQLDbType::Noggit));
|
||||||
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -234,15 +275,13 @@ namespace Noggit
|
|||||||
ui->_wmo_aabb->setChecked(_settings->value("render/wmo_aabb", false).toBool());
|
ui->_wmo_aabb->setChecked(_settings->value("render/wmo_aabb", false).toBool());
|
||||||
ui->_wmo_group_bounds->setChecked(_settings->value("render/wmo_groups_bounds", false).toBool());
|
ui->_wmo_group_bounds->setChecked(_settings->value("render/wmo_groups_bounds", false).toBool());
|
||||||
|
|
||||||
|
|
||||||
#ifdef USE_MYSQL_UID_STORAGE
|
|
||||||
ui->MySQL_box->setChecked (_settings->value ("project/mysql/enabled").toBool());
|
ui->MySQL_box->setChecked (_settings->value ("project/mysql/enabled").toBool());
|
||||||
|
|
||||||
auto server_str = _settings->value("project/mysql/server", "127.0.0.1").toString();
|
auto server_str = _settings->value("project/mysql/server", "127.0.0.1").toString();
|
||||||
auto user_str = _settings->value("project/mysql/user", "127.0.0.1").toString();
|
auto user_str = _settings->value("project/mysql/user", "root").toString();
|
||||||
auto pwd_str = _settings->value("project/mysql/pwd", "127.0.0.1").toString();
|
auto pwd_str = _settings->value("project/mysql/pwd", "root").toString();
|
||||||
auto db_str = _settings->value("project/mysql/db", "127.0.0.1").toString();
|
auto db_str = _settings->value("project/mysql/db", "noggit").toString();
|
||||||
auto port_int = _settings->value("project/mysql/port", "127.0.0.1").toInt();
|
auto port_int = _settings->value("project/mysql/port", "3306").toInt();
|
||||||
|
|
||||||
// set some default
|
// set some default
|
||||||
if (server_str.isEmpty())
|
if (server_str.isEmpty())
|
||||||
@@ -261,7 +300,6 @@ namespace Noggit
|
|||||||
ui->_mysql_pwd_field->setText (pwd_str);
|
ui->_mysql_pwd_field->setText (pwd_str);
|
||||||
ui->_mysql_db_field->setText (db_str);
|
ui->_mysql_db_field->setText (db_str);
|
||||||
ui->_mysql_port_field->setValue (port_int);
|
ui->_mysql_port_field->setValue (port_int);
|
||||||
#endif
|
|
||||||
|
|
||||||
bool wireframe_type = _settings->value("wireframe/type", false).toBool();
|
bool wireframe_type = _settings->value("wireframe/type", false).toBool();
|
||||||
|
|
||||||
@@ -308,14 +346,12 @@ namespace Noggit
|
|||||||
_settings->setValue("modern_features", ui->_modern_features->isChecked());
|
_settings->setValue("modern_features", ui->_modern_features->isChecked());
|
||||||
_settings->setValue("use_mclq_liquids_export", ui->_use_mclq_liquids_export->isChecked());
|
_settings->setValue("use_mclq_liquids_export", ui->_use_mclq_liquids_export->isChecked());
|
||||||
|
|
||||||
#ifdef USE_MYSQL_UID_STORAGE
|
|
||||||
_settings->setValue ("project/mysql/enabled", ui->MySQL_box->isChecked());
|
_settings->setValue ("project/mysql/enabled", ui->MySQL_box->isChecked());
|
||||||
_settings->setValue ("project/mysql/server", ui->_mysql_server_field->text());
|
_settings->setValue ("project/mysql/server", ui->_mysql_server_field->text());
|
||||||
_settings->setValue ("project/mysql/user", ui->_mysql_user_field->text());
|
_settings->setValue ("project/mysql/user", ui->_mysql_user_field->text());
|
||||||
_settings->setValue ("project/mysql/pwd", ui->_mysql_pwd_field->text());
|
_settings->setValue ("project/mysql/pwd", ui->_mysql_pwd_field->text());
|
||||||
_settings->setValue ("project/mysql/db", ui->_mysql_db_field->text());
|
_settings->setValue ("project/mysql/db", ui->_mysql_db_field->text());
|
||||||
_settings->setValue ("project/mysql/port", ui->_mysql_port_field->text());
|
_settings->setValue ("project/mysql/port", ui->_mysql_port_field->text());
|
||||||
#endif
|
|
||||||
|
|
||||||
_settings->setValue("wireframe/type", ui->radio_wire_cursor->isChecked());
|
_settings->setValue("wireframe/type", ui->radio_wire_cursor->isChecked());
|
||||||
_settings->setValue("wireframe/radius", ui->_wireframe_radius->value());
|
_settings->setValue("wireframe/radius", ui->_wireframe_radius->value());
|
||||||
@@ -338,6 +374,18 @@ namespace Noggit
|
|||||||
|
|
||||||
_settings->sync();
|
_settings->sync();
|
||||||
|
|
||||||
|
// reinitialize db on save
|
||||||
|
auto& db_manager = Sql::DatabaseManager::instance();
|
||||||
|
QString host = _settings->value("project/mysql/server").toString();
|
||||||
|
int port = _settings->value("project/mysql/port", "3306").toInt();
|
||||||
|
QString db_name = _settings->value("project/mysql/db").toString();
|
||||||
|
QString user = _settings->value("project/mysql/user").toString();
|
||||||
|
QString pass = _settings->value("project/mysql/pwd").toString();
|
||||||
|
|
||||||
|
bool test1 = db_manager.initializeDb(Sql::SQLDbType::Noggit, host, port, db_name, user, pass);
|
||||||
|
bool test2 = db_manager.testConnectionWithPopup(Sql::SQLDbType::Noggit, true);
|
||||||
|
|
||||||
|
|
||||||
// calls MapView::onSettingsSave()
|
// calls MapView::onSettingsSave()
|
||||||
emit saved();
|
emit saved();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user