From 83c46e8746e407fe023f762e735b9796414d0454 Mon Sep 17 00:00:00 2001 From: Popa Adrian Marius Date: Fri, 5 Jun 2026 00:02:30 +0300 Subject: [PATCH 1/4] Implement Service Manager API to set replica mode (#52) --- src/fb-cpp/BackupManager.cpp | 18 +++++ src/fb-cpp/BackupManager.h | 18 +++++ src/fb-cpp/ConfigManager.cpp | 63 +++++++++++++++ src/fb-cpp/ConfigManager.h | 100 ++++++++++++++++++++++++ src/fb-cpp/ServiceManager.h | 21 +++++ src/fb-cpp/fb-cpp.h | 1 + src/test/ConfigManager.cpp | 145 +++++++++++++++++++++++++++++++++++ 7 files changed, 366 insertions(+) create mode 100644 src/fb-cpp/ConfigManager.cpp create mode 100644 src/fb-cpp/ConfigManager.h create mode 100644 src/test/ConfigManager.cpp diff --git a/src/fb-cpp/BackupManager.cpp b/src/fb-cpp/BackupManager.cpp index 9aa38d9..46ebce9 100644 --- a/src/fb-cpp/BackupManager.cpp +++ b/src/fb-cpp/BackupManager.cpp @@ -84,6 +84,24 @@ void BackupManager::restore(const RestoreOptions& options) if (const auto parallelWorkers = options.getParallelWorkers()) builder->insertInt(&statusWrapper, isc_spb_res_parallel_workers, static_cast(*parallelWorkers)); + if (const auto replicaMode = options.getReplicaMode()) + { + std::uint8_t modeVal = 0; + switch (*replicaMode) + { + case ReplicaMode::NONE: + modeVal = isc_spb_res_rm_none; + break; + case ReplicaMode::READ_ONLY: + modeVal = isc_spb_res_rm_readonly; + break; + case ReplicaMode::READ_WRITE: + modeVal = isc_spb_res_rm_readwrite; + break; + } + builder->insertBytes(&statusWrapper, isc_spb_res_replica_mode, &modeVal, 1u); + } + const auto buffer = builder->getBuffer(&statusWrapper); const auto length = builder->getBufferLength(&statusWrapper); diff --git a/src/fb-cpp/BackupManager.h b/src/fb-cpp/BackupManager.h index 137c3d9..89b3bb1 100644 --- a/src/fb-cpp/BackupManager.h +++ b/src/fb-cpp/BackupManager.h @@ -296,12 +296,30 @@ namespace fbcpp return *this; } + /// + /// Returns the replica mode. + /// + const std::optional& getReplicaMode() const + { + return replicaMode; + } + + /// + /// Sets the replica mode. + /// + RestoreOptions& setReplicaMode(ReplicaMode value) + { + replicaMode = value; + return *this; + } + private: std::vector databaseFiles; std::vector backupFiles; bool replace = false; ServiceManager::VerboseOutput verboseOutput; std::optional parallelWorkers; + std::optional replicaMode; }; /// diff --git a/src/fb-cpp/ConfigManager.cpp b/src/fb-cpp/ConfigManager.cpp new file mode 100644 index 0000000..640b5db --- /dev/null +++ b/src/fb-cpp/ConfigManager.cpp @@ -0,0 +1,63 @@ +/* + * MIT License + * + * Copyright (c) 2026 Popa Adrian Marius + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "ConfigManager.h" +#include "Client.h" + +using namespace fbcpp; +using namespace fbcpp::impl; + + +void ConfigManager::configure(const ConfigOptions& options) +{ + StatusWrapper statusWrapper{getClient()}; + auto builder = + fbUnique(getClient().getUtil()->getXpbBuilder(&statusWrapper, fb::IXpbBuilder::SPB_START, nullptr, 0)); + builder->insertTag(&statusWrapper, isc_action_svc_properties); + builder->insertString(&statusWrapper, isc_spb_dbname, options.getDatabase().c_str()); + + if (const auto replicaMode = options.getReplicaMode()) + { + std::uint8_t modeVal = 0; + switch (*replicaMode) + { + case ReplicaMode::NONE: + modeVal = isc_spb_prp_rm_none; + break; + case ReplicaMode::READ_ONLY: + modeVal = isc_spb_prp_rm_readonly; + break; + case ReplicaMode::READ_WRITE: + modeVal = isc_spb_prp_rm_readwrite; + break; + } + builder->insertBytes(&statusWrapper, isc_spb_prp_replica_mode, &modeVal, 1u); + } + + const auto buffer = builder->getBuffer(&statusWrapper); + const auto length = builder->getBufferLength(&statusWrapper); + + startAction(std::vector(buffer, buffer + length)); + waitForCompletion(); +} diff --git a/src/fb-cpp/ConfigManager.h b/src/fb-cpp/ConfigManager.h new file mode 100644 index 0000000..59d8f29 --- /dev/null +++ b/src/fb-cpp/ConfigManager.h @@ -0,0 +1,100 @@ +/* + * MIT License + * + * Copyright (c) 2026 Popa Adrian Marius + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef FBCPP_CONFIG_MANAGER_H +#define FBCPP_CONFIG_MANAGER_H + +#include "ServiceManager.h" +#include +#include + + +/// +/// fb-cpp namespace. +/// +namespace fbcpp +{ + /// + /// Represents options used to configure database properties through the service manager. + /// + class ConfigOptions final + { + public: + /// + /// Returns the database path to be configured. + /// + const std::string& getDatabase() const + { + return database; + } + + /// + /// Sets the database path to be configured. + /// + ConfigOptions& setDatabase(const std::string& value) + { + database = value; + return *this; + } + + /// + /// Returns the replica mode. + /// + const std::optional& getReplicaMode() const + { + return replicaMode; + } + + /// + /// Sets the replica mode. + /// + ConfigOptions& setReplicaMode(ReplicaMode value) + { + replicaMode = value; + return *this; + } + + private: + std::string database; + std::optional replicaMode; + }; + + /// + /// Executes configuration and maintenance operations through the Firebird service manager. + /// + class ConfigManager final : public ServiceManager + { + public: + using ServiceManager::ServiceManager; + + public: + /// + /// Configures database properties using the provided options. + /// + void configure(const ConfigOptions& options); + }; +} // namespace fbcpp + + +#endif // FBCPP_CONFIG_MANAGER_H diff --git a/src/fb-cpp/ServiceManager.h b/src/fb-cpp/ServiceManager.h index 46d0440..ebe2815 100644 --- a/src/fb-cpp/ServiceManager.h +++ b/src/fb-cpp/ServiceManager.h @@ -42,6 +42,27 @@ /// namespace fbcpp { + /// + /// Replica mode. + /// + enum class ReplicaMode + { + /// + /// The database is not a replica (operates as primary). + /// + NONE, + + /// + /// Read-only replica. + /// + READ_ONLY, + + /// + /// Read-write replica. + /// + READ_WRITE + }; + class Client; /// diff --git a/src/fb-cpp/fb-cpp.h b/src/fb-cpp/fb-cpp.h index a0fa3db..4960180 100644 --- a/src/fb-cpp/fb-cpp.h +++ b/src/fb-cpp/fb-cpp.h @@ -36,5 +36,6 @@ #include "EventListener.h" #include "ServiceManager.h" #include "BackupManager.h" +#include "ConfigManager.h" #endif // FBCPP_H diff --git a/src/test/ConfigManager.cpp b/src/test/ConfigManager.cpp new file mode 100644 index 0000000..03f1f4b --- /dev/null +++ b/src/test/ConfigManager.cpp @@ -0,0 +1,145 @@ +/* + * MIT License + * + * Copyright (c) 2026 Popa Adrian Marius + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "TestUtil.h" +#include "fb-cpp/BackupManager.h" +#include "fb-cpp/ConfigManager.h" +#include "fb-cpp/Exception.h" +#include "fb-cpp/Statement.h" +#include "fb-cpp/Transaction.h" +#include + +namespace +{ + ServiceManagerOptions makeServiceManagerOptions() + { + auto options = ServiceManagerOptions{}; + + if (const auto server = getServer()) + options.setServer(server.value()); + + return options; + } +} // namespace + +BOOST_AUTO_TEST_SUITE(ConfigManagerSuite) + +BOOST_AUTO_TEST_CASE(setReplicaModeNone) +{ + const auto databasePath = getTempFile("ConfigManager-setReplicaModeNone.fdb", false); + const auto databaseUri = getTempFile("ConfigManager-setReplicaModeNone.fdb"); + const auto attachmentOptions = AttachmentOptions().setConnectionCharSet("UTF8"); + + { // scope + Attachment attachment{ + CLIENT, databaseUri, AttachmentOptions().setCreateDatabase(true).setConnectionCharSet("UTF8")}; + Transaction transaction{attachment}; + + Statement queryContext{attachment, transaction, "select rdb$get_context('SYSTEM', 'REPLICA_MODE') from rdb$database"}; + BOOST_REQUIRE(queryContext.execute(transaction)); + BOOST_CHECK(!queryContext.getString(0).has_value()); + + Statement queryMon{attachment, transaction, "select mon$replica_mode from mon$database"}; + BOOST_REQUIRE(queryMon.execute(transaction)); + BOOST_CHECK_EQUAL(queryMon.getInt32(0).value(), 0); + } + + ConfigManager manager{CLIENT, makeServiceManagerOptions()}; + manager.configure(ConfigOptions().setDatabase(databasePath).setReplicaMode(ReplicaMode::READ_ONLY)); + + { // scope + Attachment attachment{CLIENT, databaseUri, attachmentOptions}; + Transaction transaction{attachment}; + + Statement queryContext{attachment, transaction, "select rdb$get_context('SYSTEM', 'REPLICA_MODE') from rdb$database"}; + BOOST_REQUIRE(queryContext.execute(transaction)); + BOOST_REQUIRE(queryContext.getString(0).has_value()); + BOOST_CHECK_EQUAL(queryContext.getString(0).value(), "READ-ONLY"); + + Statement queryMon{attachment, transaction, "select mon$replica_mode from mon$database"}; + BOOST_REQUIRE(queryMon.execute(transaction)); + BOOST_CHECK_EQUAL(queryMon.getInt32(0).value(), 1); + } + + manager.configure(ConfigOptions().setDatabase(databasePath).setReplicaMode(ReplicaMode::NONE)); + + { // scope + Attachment attachment{CLIENT, databaseUri, attachmentOptions}; + Transaction transaction{attachment}; + + Statement queryContext{attachment, transaction, "select rdb$get_context('SYSTEM', 'REPLICA_MODE') from rdb$database"}; + BOOST_REQUIRE(queryContext.execute(transaction)); + BOOST_CHECK(!queryContext.getString(0).has_value()); + + Statement queryMon{attachment, transaction, "select mon$replica_mode from mon$database"}; + BOOST_REQUIRE(queryMon.execute(transaction)); + BOOST_CHECK_EQUAL(queryMon.getInt32(0).value(), 0); + } + + Attachment cleanup{CLIENT, databaseUri, attachmentOptions}; + cleanup.dropDatabase(); +} + +BOOST_AUTO_TEST_CASE(restoreWithReplicaMode) +{ + const auto sourceDatabasePath = getTempFile("ConfigManager-restoreReplica-source.fdb", false); + const auto restoredDatabasePath = getTempFile("ConfigManager-restoreReplica-restored.fdb", false); + const auto backupFile = getTempFile("ConfigManager-restoreReplica.fbk", false); + const auto sourceDatabaseUri = getTempFile("ConfigManager-restoreReplica-source.fdb"); + const auto restoredDatabaseUri = getTempFile("ConfigManager-restoreReplica-restored.fdb"); + const auto attachmentOptions = AttachmentOptions().setConnectionCharSet("UTF8"); + + { // scope + Attachment attachment{ + CLIENT, sourceDatabaseUri, AttachmentOptions().setCreateDatabase(true).setConnectionCharSet("UTF8")}; + Transaction transaction{attachment}; + Statement create{attachment, transaction, "create table test(id integer)"}; + create.execute(transaction); + transaction.commit(); + } + + BackupManager backupManager{CLIENT, makeServiceManagerOptions()}; + backupManager.backup(BackupOptions().setDatabase(sourceDatabasePath).setBackupFile(backupFile)); + backupManager.restore(RestoreOptions().setDatabase(restoredDatabasePath).setBackupFile(backupFile).setReplicaMode(ReplicaMode::READ_WRITE)); + + { // scope + Attachment restored{CLIENT, restoredDatabaseUri, attachmentOptions}; + FbDropDatabase restoredDrop{restored}; + Transaction transaction{restored}; + + Statement queryContext{restored, transaction, "select rdb$get_context('SYSTEM', 'REPLICA_MODE') from rdb$database"}; + BOOST_REQUIRE(queryContext.execute(transaction)); + BOOST_REQUIRE(queryContext.getString(0).has_value()); + BOOST_CHECK_EQUAL(queryContext.getString(0).value(), "READ-WRITE"); + + Statement queryMon{restored, transaction, "select mon$replica_mode from mon$database"}; + BOOST_REQUIRE(queryMon.execute(transaction)); + BOOST_CHECK_EQUAL(queryMon.getInt32(0).value(), 2); + } + + Attachment cleanup{CLIENT, sourceDatabaseUri, attachmentOptions}; + cleanup.dropDatabase(); +} + +BOOST_AUTO_TEST_SUITE_END() From 85c2dd8704b7f189ee1898499a5f18a61e11f9f1 Mon Sep 17 00:00:00 2001 From: Popa Adrian Marius Date: Fri, 5 Jun 2026 18:34:21 +0300 Subject: [PATCH 2/4] Rename ConfigManager to DatabaseManager --- ...{ConfigManager.cpp => DatabaseManager.cpp} | 4 ++-- .../{ConfigManager.h => DatabaseManager.h} | 16 ++++++------- src/fb-cpp/fb-cpp.h | 2 +- ...{ConfigManager.cpp => DatabaseManager.cpp} | 24 +++++++++---------- 4 files changed, 23 insertions(+), 23 deletions(-) rename src/fb-cpp/{ConfigManager.cpp => DatabaseManager.cpp} (95%) rename src/fb-cpp/{ConfigManager.h => DatabaseManager.h} (86%) rename src/test/{ConfigManager.cpp => DatabaseManager.cpp} (83%) diff --git a/src/fb-cpp/ConfigManager.cpp b/src/fb-cpp/DatabaseManager.cpp similarity index 95% rename from src/fb-cpp/ConfigManager.cpp rename to src/fb-cpp/DatabaseManager.cpp index 640b5db..47559e0 100644 --- a/src/fb-cpp/ConfigManager.cpp +++ b/src/fb-cpp/DatabaseManager.cpp @@ -22,14 +22,14 @@ * SOFTWARE. */ -#include "ConfigManager.h" +#include "DatabaseManager.h" #include "Client.h" using namespace fbcpp; using namespace fbcpp::impl; -void ConfigManager::configure(const ConfigOptions& options) +void DatabaseManager::configure(const DatabaseOptions& options) { StatusWrapper statusWrapper{getClient()}; auto builder = diff --git a/src/fb-cpp/ConfigManager.h b/src/fb-cpp/DatabaseManager.h similarity index 86% rename from src/fb-cpp/ConfigManager.h rename to src/fb-cpp/DatabaseManager.h index 59d8f29..e26c6df 100644 --- a/src/fb-cpp/ConfigManager.h +++ b/src/fb-cpp/DatabaseManager.h @@ -22,8 +22,8 @@ * SOFTWARE. */ -#ifndef FBCPP_CONFIG_MANAGER_H -#define FBCPP_CONFIG_MANAGER_H +#ifndef FBCPP_DATABASE_MANAGER_H +#define FBCPP_DATABASE_MANAGER_H #include "ServiceManager.h" #include @@ -38,7 +38,7 @@ namespace fbcpp /// /// Represents options used to configure database properties through the service manager. /// - class ConfigOptions final + class DatabaseOptions final { public: /// @@ -52,7 +52,7 @@ namespace fbcpp /// /// Sets the database path to be configured. /// - ConfigOptions& setDatabase(const std::string& value) + DatabaseOptions& setDatabase(const std::string& value) { database = value; return *this; @@ -69,7 +69,7 @@ namespace fbcpp /// /// Sets the replica mode. /// - ConfigOptions& setReplicaMode(ReplicaMode value) + DatabaseOptions& setReplicaMode(ReplicaMode value) { replicaMode = value; return *this; @@ -83,7 +83,7 @@ namespace fbcpp /// /// Executes configuration and maintenance operations through the Firebird service manager. /// - class ConfigManager final : public ServiceManager + class DatabaseManager final : public ServiceManager { public: using ServiceManager::ServiceManager; @@ -92,9 +92,9 @@ namespace fbcpp /// /// Configures database properties using the provided options. /// - void configure(const ConfigOptions& options); + void configure(const DatabaseOptions& options); }; } // namespace fbcpp -#endif // FBCPP_CONFIG_MANAGER_H +#endif // FBCPP_DATABASE_MANAGER_H diff --git a/src/fb-cpp/fb-cpp.h b/src/fb-cpp/fb-cpp.h index 4960180..b3f8fc8 100644 --- a/src/fb-cpp/fb-cpp.h +++ b/src/fb-cpp/fb-cpp.h @@ -36,6 +36,6 @@ #include "EventListener.h" #include "ServiceManager.h" #include "BackupManager.h" -#include "ConfigManager.h" +#include "DatabaseManager.h" #endif // FBCPP_H diff --git a/src/test/ConfigManager.cpp b/src/test/DatabaseManager.cpp similarity index 83% rename from src/test/ConfigManager.cpp rename to src/test/DatabaseManager.cpp index 03f1f4b..c26be16 100644 --- a/src/test/ConfigManager.cpp +++ b/src/test/DatabaseManager.cpp @@ -24,7 +24,7 @@ #include "TestUtil.h" #include "fb-cpp/BackupManager.h" -#include "fb-cpp/ConfigManager.h" +#include "fb-cpp/DatabaseManager.h" #include "fb-cpp/Exception.h" #include "fb-cpp/Statement.h" #include "fb-cpp/Transaction.h" @@ -43,12 +43,12 @@ namespace } } // namespace -BOOST_AUTO_TEST_SUITE(ConfigManagerSuite) +BOOST_AUTO_TEST_SUITE(DatabaseManagerSuite) BOOST_AUTO_TEST_CASE(setReplicaModeNone) { - const auto databasePath = getTempFile("ConfigManager-setReplicaModeNone.fdb", false); - const auto databaseUri = getTempFile("ConfigManager-setReplicaModeNone.fdb"); + const auto databasePath = getTempFile("DatabaseManager-setReplicaModeNone.fdb", false); + const auto databaseUri = getTempFile("DatabaseManager-setReplicaModeNone.fdb"); const auto attachmentOptions = AttachmentOptions().setConnectionCharSet("UTF8"); { // scope @@ -65,8 +65,8 @@ BOOST_AUTO_TEST_CASE(setReplicaModeNone) BOOST_CHECK_EQUAL(queryMon.getInt32(0).value(), 0); } - ConfigManager manager{CLIENT, makeServiceManagerOptions()}; - manager.configure(ConfigOptions().setDatabase(databasePath).setReplicaMode(ReplicaMode::READ_ONLY)); + DatabaseManager manager{CLIENT, makeServiceManagerOptions()}; + manager.configure(DatabaseOptions().setDatabase(databasePath).setReplicaMode(ReplicaMode::READ_ONLY)); { // scope Attachment attachment{CLIENT, databaseUri, attachmentOptions}; @@ -82,7 +82,7 @@ BOOST_AUTO_TEST_CASE(setReplicaModeNone) BOOST_CHECK_EQUAL(queryMon.getInt32(0).value(), 1); } - manager.configure(ConfigOptions().setDatabase(databasePath).setReplicaMode(ReplicaMode::NONE)); + manager.configure(DatabaseOptions().setDatabase(databasePath).setReplicaMode(ReplicaMode::NONE)); { // scope Attachment attachment{CLIENT, databaseUri, attachmentOptions}; @@ -103,11 +103,11 @@ BOOST_AUTO_TEST_CASE(setReplicaModeNone) BOOST_AUTO_TEST_CASE(restoreWithReplicaMode) { - const auto sourceDatabasePath = getTempFile("ConfigManager-restoreReplica-source.fdb", false); - const auto restoredDatabasePath = getTempFile("ConfigManager-restoreReplica-restored.fdb", false); - const auto backupFile = getTempFile("ConfigManager-restoreReplica.fbk", false); - const auto sourceDatabaseUri = getTempFile("ConfigManager-restoreReplica-source.fdb"); - const auto restoredDatabaseUri = getTempFile("ConfigManager-restoreReplica-restored.fdb"); + const auto sourceDatabasePath = getTempFile("DatabaseManager-restoreReplica-source.fdb", false); + const auto restoredDatabasePath = getTempFile("DatabaseManager-restoreReplica-restored.fdb", false); + const auto backupFile = getTempFile("DatabaseManager-restoreReplica.fbk", false); + const auto sourceDatabaseUri = getTempFile("DatabaseManager-restoreReplica-source.fdb"); + const auto restoredDatabaseUri = getTempFile("DatabaseManager-restoreReplica-restored.fdb"); const auto attachmentOptions = AttachmentOptions().setConnectionCharSet("UTF8"); { // scope From 111299ac8644340b52e9045dd15fe64abe46d0b3 Mon Sep 17 00:00:00 2001 From: Popa Adrian Marius Date: Fri, 5 Jun 2026 18:48:38 +0300 Subject: [PATCH 3/4] Format test file DatabaseManager.cpp --- src/test/DatabaseManager.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/test/DatabaseManager.cpp b/src/test/DatabaseManager.cpp index c26be16..dc20047 100644 --- a/src/test/DatabaseManager.cpp +++ b/src/test/DatabaseManager.cpp @@ -56,7 +56,8 @@ BOOST_AUTO_TEST_CASE(setReplicaModeNone) CLIENT, databaseUri, AttachmentOptions().setCreateDatabase(true).setConnectionCharSet("UTF8")}; Transaction transaction{attachment}; - Statement queryContext{attachment, transaction, "select rdb$get_context('SYSTEM', 'REPLICA_MODE') from rdb$database"}; + Statement queryContext{ + attachment, transaction, "select rdb$get_context('SYSTEM', 'REPLICA_MODE') from rdb$database"}; BOOST_REQUIRE(queryContext.execute(transaction)); BOOST_CHECK(!queryContext.getString(0).has_value()); @@ -72,7 +73,8 @@ BOOST_AUTO_TEST_CASE(setReplicaModeNone) Attachment attachment{CLIENT, databaseUri, attachmentOptions}; Transaction transaction{attachment}; - Statement queryContext{attachment, transaction, "select rdb$get_context('SYSTEM', 'REPLICA_MODE') from rdb$database"}; + Statement queryContext{ + attachment, transaction, "select rdb$get_context('SYSTEM', 'REPLICA_MODE') from rdb$database"}; BOOST_REQUIRE(queryContext.execute(transaction)); BOOST_REQUIRE(queryContext.getString(0).has_value()); BOOST_CHECK_EQUAL(queryContext.getString(0).value(), "READ-ONLY"); @@ -88,7 +90,8 @@ BOOST_AUTO_TEST_CASE(setReplicaModeNone) Attachment attachment{CLIENT, databaseUri, attachmentOptions}; Transaction transaction{attachment}; - Statement queryContext{attachment, transaction, "select rdb$get_context('SYSTEM', 'REPLICA_MODE') from rdb$database"}; + Statement queryContext{ + attachment, transaction, "select rdb$get_context('SYSTEM', 'REPLICA_MODE') from rdb$database"}; BOOST_REQUIRE(queryContext.execute(transaction)); BOOST_CHECK(!queryContext.getString(0).has_value()); @@ -121,14 +124,18 @@ BOOST_AUTO_TEST_CASE(restoreWithReplicaMode) BackupManager backupManager{CLIENT, makeServiceManagerOptions()}; backupManager.backup(BackupOptions().setDatabase(sourceDatabasePath).setBackupFile(backupFile)); - backupManager.restore(RestoreOptions().setDatabase(restoredDatabasePath).setBackupFile(backupFile).setReplicaMode(ReplicaMode::READ_WRITE)); + backupManager.restore(RestoreOptions() + .setDatabase(restoredDatabasePath) + .setBackupFile(backupFile) + .setReplicaMode(ReplicaMode::READ_WRITE)); { // scope Attachment restored{CLIENT, restoredDatabaseUri, attachmentOptions}; FbDropDatabase restoredDrop{restored}; Transaction transaction{restored}; - Statement queryContext{restored, transaction, "select rdb$get_context('SYSTEM', 'REPLICA_MODE') from rdb$database"}; + Statement queryContext{ + restored, transaction, "select rdb$get_context('SYSTEM', 'REPLICA_MODE') from rdb$database"}; BOOST_REQUIRE(queryContext.execute(transaction)); BOOST_REQUIRE(queryContext.getString(0).has_value()); BOOST_CHECK_EQUAL(queryContext.getString(0).value(), "READ-WRITE"); From 3b222a1d734a8fd5ca1a377dd45bdb7af6fb1a90 Mon Sep 17 00:00:00 2001 From: Popa Adrian Marius Date: Fri, 5 Jun 2026 23:57:06 +0300 Subject: [PATCH 4/4] Address review feedback: rename DatabaseOptions to DatabaseManagerOptions, configure to execute, and add default assert(false) cases --- src/fb-cpp/BackupManager.cpp | 4 ++++ src/fb-cpp/DatabaseManager.cpp | 6 +++++- src/fb-cpp/DatabaseManager.h | 8 ++++---- src/test/DatabaseManager.cpp | 4 ++-- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/fb-cpp/BackupManager.cpp b/src/fb-cpp/BackupManager.cpp index 46ebce9..c6fb001 100644 --- a/src/fb-cpp/BackupManager.cpp +++ b/src/fb-cpp/BackupManager.cpp @@ -24,6 +24,7 @@ #include "BackupManager.h" #include "Client.h" +#include using namespace fbcpp; using namespace fbcpp::impl; @@ -98,6 +99,9 @@ void BackupManager::restore(const RestoreOptions& options) case ReplicaMode::READ_WRITE: modeVal = isc_spb_res_rm_readwrite; break; + default: + assert(false); + break; } builder->insertBytes(&statusWrapper, isc_spb_res_replica_mode, &modeVal, 1u); } diff --git a/src/fb-cpp/DatabaseManager.cpp b/src/fb-cpp/DatabaseManager.cpp index 47559e0..0614295 100644 --- a/src/fb-cpp/DatabaseManager.cpp +++ b/src/fb-cpp/DatabaseManager.cpp @@ -24,12 +24,13 @@ #include "DatabaseManager.h" #include "Client.h" +#include using namespace fbcpp; using namespace fbcpp::impl; -void DatabaseManager::configure(const DatabaseOptions& options) +void DatabaseManager::execute(const DatabaseManagerOptions& options) { StatusWrapper statusWrapper{getClient()}; auto builder = @@ -51,6 +52,9 @@ void DatabaseManager::configure(const DatabaseOptions& options) case ReplicaMode::READ_WRITE: modeVal = isc_spb_prp_rm_readwrite; break; + default: + assert(false); + break; } builder->insertBytes(&statusWrapper, isc_spb_prp_replica_mode, &modeVal, 1u); } diff --git a/src/fb-cpp/DatabaseManager.h b/src/fb-cpp/DatabaseManager.h index e26c6df..887b377 100644 --- a/src/fb-cpp/DatabaseManager.h +++ b/src/fb-cpp/DatabaseManager.h @@ -38,7 +38,7 @@ namespace fbcpp /// /// Represents options used to configure database properties through the service manager. /// - class DatabaseOptions final + class DatabaseManagerOptions final { public: /// @@ -52,7 +52,7 @@ namespace fbcpp /// /// Sets the database path to be configured. /// - DatabaseOptions& setDatabase(const std::string& value) + DatabaseManagerOptions& setDatabase(const std::string& value) { database = value; return *this; @@ -69,7 +69,7 @@ namespace fbcpp /// /// Sets the replica mode. /// - DatabaseOptions& setReplicaMode(ReplicaMode value) + DatabaseManagerOptions& setReplicaMode(ReplicaMode value) { replicaMode = value; return *this; @@ -92,7 +92,7 @@ namespace fbcpp /// /// Configures database properties using the provided options. /// - void configure(const DatabaseOptions& options); + void execute(const DatabaseManagerOptions& options); }; } // namespace fbcpp diff --git a/src/test/DatabaseManager.cpp b/src/test/DatabaseManager.cpp index dc20047..8e86045 100644 --- a/src/test/DatabaseManager.cpp +++ b/src/test/DatabaseManager.cpp @@ -67,7 +67,7 @@ BOOST_AUTO_TEST_CASE(setReplicaModeNone) } DatabaseManager manager{CLIENT, makeServiceManagerOptions()}; - manager.configure(DatabaseOptions().setDatabase(databasePath).setReplicaMode(ReplicaMode::READ_ONLY)); + manager.execute(DatabaseManagerOptions().setDatabase(databasePath).setReplicaMode(ReplicaMode::READ_ONLY)); { // scope Attachment attachment{CLIENT, databaseUri, attachmentOptions}; @@ -84,7 +84,7 @@ BOOST_AUTO_TEST_CASE(setReplicaModeNone) BOOST_CHECK_EQUAL(queryMon.getInt32(0).value(), 1); } - manager.configure(DatabaseOptions().setDatabase(databasePath).setReplicaMode(ReplicaMode::NONE)); + manager.execute(DatabaseManagerOptions().setDatabase(databasePath).setReplicaMode(ReplicaMode::NONE)); { // scope Attachment attachment{CLIENT, databaseUri, attachmentOptions};