From 6e27e2c7e4aa562e2bb2518918bb753f235bb725 Mon Sep 17 00:00:00 2001 From: Y_Less Date: Wed, 28 Dec 2022 12:24:19 +0000 Subject: [PATCH 1/3] Deal with various in-memory db opening methods. --- .../Pawn/Scripting/Database/Natives.cpp | 94 ++++++++++++++++++- 1 file changed, 90 insertions(+), 4 deletions(-) diff --git a/Server/Components/Pawn/Scripting/Database/Natives.cpp b/Server/Components/Pawn/Scripting/Database/Natives.cpp index ee6db83e8..f8967da07 100644 --- a/Server/Components/Pawn/Scripting/Database/Natives.cpp +++ b/Server/Components/Pawn/Scripting/Database/Natives.cpp @@ -11,10 +11,87 @@ #include #include "../../format.hpp" +static IDatabaseConnection* doDBOpen(const std::string& name, int flags) +{ + size_t start; + size_t end; + + // Get the protocol. + String protocol = name.substr(0, 5); + if (protocol == "file:") + { + // We always use an aboslute path, even when a relative path is given. + protocol = "file:///"; + // URI mode. + if (name[5] == '/' && name[6] == '/') + { + // Skip the next `/`. + start = name.find('/', 7) + 1; + if (start == 0) + { + return 0; + } + } + else + { + start = 5; + } + } + else + { + protocol = ""; + start = 0; + } + + // Get the parameters. + String parameters; + end = name.find('?', start); + if (end == std::string::npos) + { + parameters = ""; + end = name.length(); + } + else + { + // There are parameters. + parameters = name.substr(end); + } + + // Get the path. + String path = name.substr(start, end - start); + + // Get the database. + if ((flags & 0x80 /* SQLITE_OPEN_MEMORY */) != 0 || path == ":memory:" || path == "" || parameters.find("mode=memory") != std::string::npos) + { + // All the ways of opening an in-memory database that I know of. + return PawnManager::Get()->databases->open(name); + } + // Should we allow this? + //else if (protocol == "file:///") + //{ + // return PawnManager::Get()->databases->open(name); + //} + else + { + // TODO: Pass in the flags. + ghc::filesystem::path dbFilePath = ghc::filesystem::absolute("scriptfiles/" + path); + return PawnManager::Get()->databases->open(protocol + dbFilePath.string() + parameters); + } +} + SCRIPT_API(db_open, int(const std::string& name)) { - ghc::filesystem::path dbFilePath = ghc::filesystem::absolute("scriptfiles/" + name); - IDatabaseConnection* database_connection(PawnManager::Get()->databases->open(dbFilePath.string())); + int flags = 0x02 /* SQLITE_OPEN_READWRITE */ | 0x04 /* SQLITE_OPEN_CREATE */; + + // Get the flags. + auto params = GetParams(); + if ((params[0] / sizeof(cell)) >= 2) + { + // Optional parameter. + flags = params[2]; + } + + IDatabaseConnection* database_connection = doDBOpen(name, flags); return database_connection ? database_connection->getID() : 0; } @@ -123,8 +200,17 @@ SCRIPT_API(db_debug_openresults, int()) SCRIPT_API(DB_Open, int(const std::string& name)) { - ghc::filesystem::path dbFilePath = ghc::filesystem::absolute("scriptfiles/" + name); - IDatabaseConnection* database_connection(PawnManager::Get()->databases->open(dbFilePath.string())); + int flags = 0x02 /* SQLITE_OPEN_READWRITE */ | 0x04 /* SQLITE_OPEN_CREATE */; + + // Get the flags. + auto params = GetParams(); + if ((params[0] / sizeof(cell)) >= 2) + { + // Optional parameter. + flags = params[2]; + } + + IDatabaseConnection* database_connection = doDBOpen(name, flags); return database_connection ? database_connection->getID() : 0; } From 14e10bfbb297316d958c3b7b14fed9b03e24b160 Mon Sep 17 00:00:00 2001 From: Y_Less Date: Wed, 28 Dec 2022 12:28:09 +0000 Subject: [PATCH 2/3] Allow passing flags to db creation. --- .../Server/Components/Databases/databases.hpp | 2 +- .../Databases/databases_component.cpp | 9 ++++++-- .../Databases/databases_component.hpp | 2 +- .../Pawn/Scripting/Database/Natives.cpp | 22 +++++++++++++------ 4 files changed, 24 insertions(+), 11 deletions(-) diff --git a/SDK/include/Server/Components/Databases/databases.hpp b/SDK/include/Server/Components/Databases/databases.hpp index 11ab4ed75..13a542e24 100644 --- a/SDK/include/Server/Components/Databases/databases.hpp +++ b/SDK/include/Server/Components/Databases/databases.hpp @@ -137,7 +137,7 @@ struct IDatabasesComponent : public IComponent /// Opens a new database connection /// @param path Path to the database /// @returns Database if successful, otherwise "nullptr" - virtual IDatabaseConnection* open(StringView path) = 0; + virtual IDatabaseConnection* open(StringView path, int flags = 0) = 0; /// Closes the specified database connection /// @param connection Database connection diff --git a/Server/Components/Databases/databases_component.cpp b/Server/Components/Databases/databases_component.cpp index b42c80e53..73dfb5685 100644 --- a/Server/Components/Databases/databases_component.cpp +++ b/Server/Components/Databases/databases_component.cpp @@ -28,11 +28,16 @@ void DatabasesComponent::onLoad(ICore* c) { } /// Opens a new database connection /// @param path Path to the database /// @returns Database if successful, otherwise "nullptr" -IDatabaseConnection* DatabasesComponent::open(StringView path) +IDatabaseConnection* DatabasesComponent::open(StringView path, int flags) { + if (flags == 0) + { + // Defaults. + flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; + } DatabaseConnection* ret(nullptr); sqlite3* database_connection_handle(nullptr); - if (sqlite3_open_v2(path.data(), &database_connection_handle, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr) == SQLITE_OK) + if (sqlite3_open_v2(path.data(), &database_connection_handle, flags, nullptr) == SQLITE_OK) { ret = databaseConnections.emplace(this, database_connection_handle); if (!ret) diff --git a/Server/Components/Databases/databases_component.hpp b/Server/Components/Databases/databases_component.hpp index 4c22b2f1c..13bd4c68e 100644 --- a/Server/Components/Databases/databases_component.hpp +++ b/Server/Components/Databases/databases_component.hpp @@ -61,7 +61,7 @@ class DatabasesComponent final : public IDatabasesComponent, public NoCopy /// @param path Path to the database /// @param outDatabaseConnectionID Database connection ID (out) /// @returns Database if successful, otherwise "nullptr" - IDatabaseConnection* open(StringView path) override; + IDatabaseConnection* open(StringView path, int flags = 0) override; /// Closes the specified database connection /// @returns "true" if database connection has been successfully closed, otherwise "false" diff --git a/Server/Components/Pawn/Scripting/Database/Natives.cpp b/Server/Components/Pawn/Scripting/Database/Natives.cpp index f8967da07..12d774465 100644 --- a/Server/Components/Pawn/Scripting/Database/Natives.cpp +++ b/Server/Components/Pawn/Scripting/Database/Natives.cpp @@ -64,32 +64,36 @@ static IDatabaseConnection* doDBOpen(const std::string& name, int flags) if ((flags & 0x80 /* SQLITE_OPEN_MEMORY */) != 0 || path == ":memory:" || path == "" || parameters.find("mode=memory") != std::string::npos) { // All the ways of opening an in-memory database that I know of. - return PawnManager::Get()->databases->open(name); + return PawnManager::Get()->databases->open(name, flags); } // Should we allow this? //else if (protocol == "file:///") //{ - // return PawnManager::Get()->databases->open(name); + // return PawnManager::Get()->databases->open(name, flags); //} else { // TODO: Pass in the flags. ghc::filesystem::path dbFilePath = ghc::filesystem::absolute("scriptfiles/" + path); - return PawnManager::Get()->databases->open(protocol + dbFilePath.string() + parameters); + return PawnManager::Get()->databases->open(protocol + dbFilePath.string() + parameters, flags); } } SCRIPT_API(db_open, int(const std::string& name)) { - int flags = 0x02 /* SQLITE_OPEN_READWRITE */ | 0x04 /* SQLITE_OPEN_CREATE */; - // Get the flags. + int flags; auto params = GetParams(); if ((params[0] / sizeof(cell)) >= 2) { // Optional parameter. flags = params[2]; } + else + { + // Defer the defaults to the implementation. + flags = 0; + } IDatabaseConnection* database_connection = doDBOpen(name, flags); return database_connection ? database_connection->getID() : 0; @@ -200,15 +204,19 @@ SCRIPT_API(db_debug_openresults, int()) SCRIPT_API(DB_Open, int(const std::string& name)) { - int flags = 0x02 /* SQLITE_OPEN_READWRITE */ | 0x04 /* SQLITE_OPEN_CREATE */; - // Get the flags. + int flags; auto params = GetParams(); if ((params[0] / sizeof(cell)) >= 2) { // Optional parameter. flags = params[2]; } + else + { + // Defer the defaults to the implementation. + flags = 0; + } IDatabaseConnection* database_connection = doDBOpen(name, flags); return database_connection ? database_connection->getID() : 0; From 7dcb91d6e639b0b106a7c2e5a1a6901e9d18b040 Mon Sep 17 00:00:00 2001 From: Y_Less Date: Wed, 28 Dec 2022 13:01:59 +0000 Subject: [PATCH 3/3] Abstract flag lookup. --- .../Pawn/Scripting/Database/Natives.cpp | 41 ++++++++----------- 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/Server/Components/Pawn/Scripting/Database/Natives.cpp b/Server/Components/Pawn/Scripting/Database/Natives.cpp index 12d774465..e06dd2856 100644 --- a/Server/Components/Pawn/Scripting/Database/Natives.cpp +++ b/Server/Components/Pawn/Scripting/Database/Natives.cpp @@ -11,6 +11,21 @@ #include #include "../../format.hpp" +static int getFlags(cell* params) +{ + // Get the flags. + if (params[0] >= 2 * sizeof(cell)) + { + // Optional parameter. + return params[2]; + } + else + { + // Defer the defaults to the implementation. + return 0; + } +} + static IDatabaseConnection* doDBOpen(const std::string& name, int flags) { size_t start; @@ -82,19 +97,8 @@ static IDatabaseConnection* doDBOpen(const std::string& name, int flags) SCRIPT_API(db_open, int(const std::string& name)) { // Get the flags. - int flags; auto params = GetParams(); - if ((params[0] / sizeof(cell)) >= 2) - { - // Optional parameter. - flags = params[2]; - } - else - { - // Defer the defaults to the implementation. - flags = 0; - } - + int flags = getFlags(params); IDatabaseConnection* database_connection = doDBOpen(name, flags); return database_connection ? database_connection->getID() : 0; } @@ -205,19 +209,8 @@ SCRIPT_API(db_debug_openresults, int()) SCRIPT_API(DB_Open, int(const std::string& name)) { // Get the flags. - int flags; auto params = GetParams(); - if ((params[0] / sizeof(cell)) >= 2) - { - // Optional parameter. - flags = params[2]; - } - else - { - // Defer the defaults to the implementation. - flags = 0; - } - + int flags = getFlags(params); IDatabaseConnection* database_connection = doDBOpen(name, flags); return database_connection ? database_connection->getID() : 0; }