diff --git a/dev/pragma.h b/dev/pragma.h index 9c51dff35..8e456c581 100644 --- a/dev/pragma.h +++ b/dev/pragma.h @@ -21,6 +21,14 @@ namespace sqlite_orm { pragma_t(get_connection_t get_connection_) : get_connection(std::move(get_connection_)) {} + void busy_timeout(int value) { + this->set_pragma("busy_timeout", value); + } + + int busy_timeout() { + return this->get_pragma("busy_timeout"); + } + sqlite_orm::journal_mode journal_mode() { return this->get_pragma("journal_mode"); } diff --git a/dev/storage_base.h b/dev/storage_base.h index fce551a0c..21dee1d52 100644 --- a/dev/storage_base.h +++ b/dev/storage_base.h @@ -302,6 +302,19 @@ namespace sqlite_orm { return this->connection->retain_count() > 0; } + int busy_handler(std::function handler) { + _busy_handler = move(handler); + if(this->is_opened()) { + if(_busy_handler) { + return sqlite3_busy_handler(this->connection->get(), busy_handler_callback, this); + } else { + return sqlite3_busy_handler(this->connection->get(), nullptr, nullptr); + } + } else { + return SQLITE_OK; + } + } + protected: storage_base(const std::string &filename_, int foreignKeysCount) : pragma(std::bind(&storage_base::get_connection, this)), @@ -339,6 +352,7 @@ namespace sqlite_orm { std::unique_ptr connection; std::map collatingFunctions; const int cachedForeignKeysCount; + std::function _busy_handler; connection_ref get_connection() { connection_ref res{*this->connection}; @@ -411,6 +425,10 @@ namespace sqlite_orm { sqlite3_limit(db, p.first, p.second); } + if(_busy_handler) { + sqlite3_busy_handler(this->connection->get(), busy_handler_callback, this); + } + if(this->on_open) { this->on_open(db); } @@ -526,6 +544,15 @@ namespace sqlite_orm { return f(leftLen, lhs, rightLen, rhs); } + static int busy_handler_callback(void *selfPointer, int triesCount) { + auto &storage = *static_cast(selfPointer); + if(storage._busy_handler) { + return storage._busy_handler(triesCount); + } else { + return 0; + } + } + // returns foreign keys count in storage definition template static int foreign_keys_count(T &storageImpl) { diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index c4b1c5f3d..2567a34f8 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -8199,6 +8199,14 @@ namespace sqlite_orm { pragma_t(get_connection_t get_connection_) : get_connection(std::move(get_connection_)) {} + void busy_timeout(int value) { + this->set_pragma("busy_timeout", value); + } + + int busy_timeout() { + return this->get_pragma("busy_timeout"); + } + sqlite_orm::journal_mode journal_mode() { return this->get_pragma("journal_mode"); } @@ -8879,6 +8887,19 @@ namespace sqlite_orm { return this->connection->retain_count() > 0; } + int busy_handler(std::function handler) { + _busy_handler = move(handler); + if(this->is_opened()) { + if(_busy_handler) { + return sqlite3_busy_handler(this->connection->get(), busy_handler_callback, this); + } else { + return sqlite3_busy_handler(this->connection->get(), nullptr, nullptr); + } + } else { + return SQLITE_OK; + } + } + protected: storage_base(const std::string &filename_, int foreignKeysCount) : pragma(std::bind(&storage_base::get_connection, this)), @@ -8916,6 +8937,7 @@ namespace sqlite_orm { std::unique_ptr connection; std::map collatingFunctions; const int cachedForeignKeysCount; + std::function _busy_handler; connection_ref get_connection() { connection_ref res{*this->connection}; @@ -8988,6 +9010,10 @@ namespace sqlite_orm { sqlite3_limit(db, p.first, p.second); } + if(_busy_handler) { + sqlite3_busy_handler(this->connection->get(), busy_handler_callback, this); + } + if(this->on_open) { this->on_open(db); } @@ -9103,6 +9129,15 @@ namespace sqlite_orm { return f(leftLen, lhs, rightLen, rhs); } + static int busy_handler_callback(void *selfPointer, int triesCount) { + auto &storage = *static_cast(selfPointer); + if(storage._busy_handler) { + return storage._busy_handler(triesCount); + } else { + return 0; + } + } + // returns foreign keys count in storage definition template static int foreign_keys_count(T &storageImpl) { diff --git a/tests/pragma_tests.cpp b/tests/pragma_tests.cpp index 564e68b8b..acec737ad 100644 --- a/tests/pragma_tests.cpp +++ b/tests/pragma_tests.cpp @@ -99,3 +99,22 @@ TEST_CASE("Auto vacuum") { storage.pragma.auto_vacuum(2); REQUIRE(storage.pragma.auto_vacuum() == 2); } + +TEST_CASE("busy_timeout") { + auto storage = make_storage({}); + + auto value = storage.pragma.busy_timeout(); + REQUIRE(value == 0); + + storage.pragma.busy_timeout(10); + value = storage.pragma.busy_timeout(); + REQUIRE(value == 10); + + storage.pragma.busy_timeout(20); + value = storage.pragma.busy_timeout(); + REQUIRE(value == 20); + + storage.pragma.busy_timeout(-1); + value = storage.pragma.busy_timeout(); + REQUIRE(value == 0); +} diff --git a/tests/storage_tests.cpp b/tests/storage_tests.cpp index 7998e36cb..3f9e1376c 100644 --- a/tests/storage_tests.cpp +++ b/tests/storage_tests.cpp @@ -3,6 +3,13 @@ using namespace sqlite_orm; +TEST_CASE("busy handler") { + auto storage = make_storage({}); + storage.busy_handler([](int /*timesCount*/) { + return 0; + }); +} + TEST_CASE("drop table") { struct User { int id = 0;